gpt4 book ai didi

c++ - 注入(inject)的类名可以用作友元声明中的类型名吗?

转载 作者:行者123 更新时间:2023-12-03 10:05:15 27 4
gpt4 key购买 nike

考虑这段代码:

template <typename T>
class Singleton
{
};

class Logger : public Singleton<Logger> {
friend class Singleton;
};
它在 gcc 和 clang 中编译,但它有效吗? [temp.local].1 说:

When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it is a template-name that refers to the class template itself.


粗体部分似乎适用, friend 声明似乎需要类型名称而不是模板名称(参见 [class.friend])。
是编译器错误还是我误读了标准?

最佳答案

[temp.local] 中的所有示例使用继承的人使用模板化的派生类,因此需要使用限定名访问基类,即通过派生类,如 [temp.local]#example-2 :

template <class T> struct Base {
Base* p;
};

template <class T> struct Derived: public Base<T> {
typename Derived::Base* p; // meaning Derived​::​Base<T>
};
这是为了克服 dependent name lookup rules .
在规范的这一部分中没有非模板 Derived 的示例,但如果 Derived 没有模板化,则以下内容也应该起作用:
// same Base as above
struct Derived: public Base<int> {
Base* p; // meaning Derived​::​Base<int>
};
这被解释为:
struct Derived: public Base<int> {
Derived::Base* p;
};
这被解释为:
struct Derived: public Base<int> {
Derived::Base<int>* p;
};
在我们的例子中:
class Logger : public Singleton<Logger> {
friend class Singleton;
};
等同于:
class Logger : public Singleton<Logger> {
friend class Logger::Singleton;
};
这与以下内容相同:
class Logger : public Singleton<Logger> {
friend class Logger::Singleton<Logger>;
};
需要注意的是规范中的定义 injected-class-name指:

The class-name is also bound in the scope of the class (template) itself; this is known as the injected-class-name.


我认为 template 这个词出现在括号中,作为规范的提示,注入(inject)的类名也可能出现在非模板类中。事实上,它在规范的其他地方使用,在非模板上下文中,例如 herehere .
为了解决这个问题,规范在 [dcl.type.simple]#note-1 处添加了:

An injected-class-name is never interpreted as a template-name in contexts where class template argument deduction would be performed ([temp.local]).


所以,我会说你的代码符合规范。

请注意 [temp.local]#example-1指编译器看不到 class Y 的情况如 Y<int>而是作为 ::Y :
template<template<class> class T> class A { };
template<class T> class Y;
template<> class Y<int> {
Y* p; // meaning Y<int>
Y<char>* q; // meaning Y<char>
A<Y>* a; // meaning A<​::​Y>
class B {
template<class> friend class Y; // meaning ​::​Y
};
};
最后一个示例也适用于我们的案例,用于声明所有类型的 Singleton 为友:
class Logger : public Singleton<Logger> {
template<class> friend class Singleton; // refers to ::Singleton
};
然而,由于 old reappearing bug in GCC,上述内容无法在 GCC 中编译。 .
为了克服 GCC 错误,可以使用更详细的选项:
class Logger : public Singleton<Logger> {
template<class> friend class ::Singleton; // OK with GCC and Clang
};
使用代码: https://godbolt.org/z/Mcez17

关于c++ - 注入(inject)的类名可以用作友元声明中的类型名吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65888872/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com