考虑以下示例:
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中,它通过了。
答案 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
函数并使用重载决策来选择合适的函数。