在类模板中可见的朋友函数名称

时间:2015-09-17 07:17:26

标签: 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);
}

使用GCC 5.2进行编译会引发以下编译错误:

no matching function for call to 'f()'

但标准在14.6.5中说:

  

可以在类模板中声明好友类或函数。   实例化模板时,会处理其朋友的名称   好像专业化在实例化时已经显式声明

为什么这不能编译?在GCC 3.4中,它通过了。

2 个答案:

答案 0 :(得分:3)

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

只需在你的[temp.inject]/2之后看到引用:

  

与非模板类一样,类模板特化的名称空间范围友元函数的名称   除非在命名空间范围(11.3)中显式声明,否则在普通查找期间不可见。这样的名字   可以根据相关类的规则找到(3.4.2)。 141

           

141) 朋友声明不会在声明模板时或在声明模板时将新名称引入任何范围   实例

答案 1 :(得分:1)

f()的调用与课程C无关,因此不会在重载解析中使用其朋友。

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