友元函数名在类模板中可见

friend function name visible in class template

本文关键字:函数 友元      更新时间:2023-10-16

考虑以下示例:

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);
}

使用GCC 5.2编译会抛出以下编译错误:

no matching function for call to 'f()'

但是标准在14.6.5中说:

友元类或函数可以在类模板中声明。当模板被实例化时,将处理它的友元名就好像特殊化在实例化时已经显式地声明了

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

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

请看你的后面的引语,[temp.inject]/2:

与非模板类一样,类的命名空间作用域友元函数的名称也是模板特化的are 在普通查找期间是不可见的,除非在命名空间作用域(11.3)中显式声明。这样的名字可以在相关类的规则(3.4.2)中找到。<一口> 141


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

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

在另一个调用f(*p)中,参数是类类型的,因此要检查类和类的名称空间以寻找可能的候选对象。这样,编译器将找到两个f函数,并使用重载解析来选择合适的一个。