让我有这样的class Foo
及其友情函数::f
:
template <typename T>
class Foo {
public:
template <typename U>
friend inline void f(Foo<T>, Foo<U>) {}
};
然后我称之为f(Foo<double>(), Foo<int>())
,
谁的朋友将是::f
?
只有Foo<double>
或它会
成为Foo<int>
的朋友,我的意思是::f
在声明时为任何Foo<T>
成为T
的朋友,或者在使用时编译生成::f
}
对于T=double
并发现它是Foo<double>
的朋友,而不是Foo<int>
的朋友?
如果我这样声明::f
:
template <typename T>
class Foo {
public:
template <typename U1, typename U2>
friend inline void f(Foo<U1>, Foo<U2>) {}
};
再次成为::f
之后成为f(Foo<double>(), Foo<int>());
的朋友
注意:仅由clang编译的第二个变体,而不是gcc。
注意,参考标准来看答案会很棒。
答案 0 :(得分:2)
您没有单一的功能模板 - 您有一个无限的系列。对于每个实例化Foo<X>
,定义了一个新的函数模板,
template <typename U>
void f(Foo<X>, Foo<U>) {}
此模板的所有实例都是Foo<X>
的朋友(但不是Foo<U>
的任何U != X
的朋友。
因此,当您编写f(Foo<double>(), Foo<int>())
时,Foo<double>
和Foo<int>
被实例化,并且使用它们,定义了f
的两个重载:
template <typename U>
void f(Foo<double>, Foo<U>) {}
template <typename U>
void f(Foo<int>, Foo<U>) {}
重载分辨率为呼叫选择第一个(第二个不可行),为U==int
实例化。此实例化f<int>(Foo<double>, Foo<int>)
是Foo<double>
的朋友,但不是Foo<int>
的朋友。
在你的第二个例子中,我相信gcc在拒绝代码方面是正确的,并且clang在接受它时是错误的(因为它的价值,MSVC同意gcc)。 Foo<X>
的每个实例都将同一模板的定义引入了封闭范围:
template <typename U1, typename U2>
void f(Foo<U1>, Foo<U2>) {}
当翻译单元执行Foo
的两个实例时,它最终会有两个相同的f
定义,因此会出错。