带有两个参数的c ++朋友函数模板

时间:2015-11-04 00:07:32

标签: c++ c++11 friend

让我有这样的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。

注意,参考标准来看答案会很棒。

1 个答案:

答案 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定义,因此会出错。