C++ 类模板中可见的友元函数名

C++ 类模板中可见的友元函数名,c++,templates,language-lawyer,friend,friend-function,C++,Templates,Language Lawyer,Friend,Friend Function,考虑以下示例: template <typename T> class C { public: friend void f() {} friend void f(C<T>) {} }; C<int> c; void g(C<int>* p) { f(); f(*p); } 但该标准在14.6.5中规定: 友元类或函数可以在类模板中声明。 当一个模板被实例化时,它的朋友的名字会被处理

考虑以下示例:

template <typename T>
class C
{
    public:
        friend void f() {}
        friend void f(C<T>) {}
};

C<int> c;

void g(C<int>* p)
{
     f(); 
     f(*p);
}
但该标准在14.6.5中规定:

友元类或函数可以在类模板中声明。 当一个模板被实例化时,它的朋友的名字会被处理 就好像专门化在实例化时被显式地声明了一样

为什么编译失败?在GCC 3.4中,它传递。

f()
的调用与类
C
没有任何关联,因此在重载解析中不使用它的友元


在另一个调用中,
f(*p)
,参数是类类型的,因此会检查类和类的名称空间是否有可能的候选者。这样,编译器将同时找到
f
函数,并使用重载解析选择合适的函数。

f
只能通过参数相关名称查找(ADL)找到。第二个调用之所以编译,是因为作为参数传递的
p
的指针对象的类型为
C
——这会导致ADL跳入并检查其他不可见的函数。事实上,根本找不到
f
的第一个重载,因为无法将关联传递给
C
的任何专门化

只要看看你后面的报价就可以了:

与非模板类一样,命名空间范围的名称是类模板专用化的友元函数 除非在命名空间范围(11.3)中明确声明,否则在普通查找过程中不可见。这样的名字 可在相关类别的规则(3.4.2)下找到。141


141)朋友声明不会在任何作用域中引入新名称,无论是在声明模板时还是在声明模板时 实例化。


请注意,如果一个模板被实例化,它的朋友将被声明,这意味着朋友名是可见的。我知道第二个可以被ADLyour找到,他说的是对的。但我的问题不是ADL。我真的想知道为什么编译不是C++规范(实例化的意思是朋友可见)。@ ZPuff[Stimulaly]意思是朋友可见的是“胡说八道”。我不能理解C++规范中真正的意思。“当一个模板被实例化时,它的朋友的名字被视为在实例化点显式声明了专门化。”)@zpeng您误解了这句话。这并没有让
朋友的形象普遍可见。而且GCC 3.4安装了可怕的窃听器,所以不要将您对该语言的理解建立在完全过时的版本上。
no matching function for call to 'f()'