GCC声明友元函数是重载的,有歧义调用,clang编译


template <typename T>
class rp {
};
template <template <typename> class P>
struct b {
    template <class, template <typename> class FriendP>
    friend void f(b<FriendP> from);
};
template <class, template <typename> class P>
void f(b<P> from) {
}
int main() {
    b<rp> v;
    f<int>(v);
    return 0;
}

Clang 3.3 (svn)编译得很好,而GCC 4.8拒绝它:

main.cpp: In function 'int main()':
main.cpp:17:10: error: call of overloaded 'f(b<rp>&)' is ambiguous
  f<int>(v);
          ^
main.cpp:17:10: note: candidates are:
main.cpp:12:6: note: void f(b<P>) [with <template-parameter-1-1> = int; P = rp]
 void f(b<P> from) {
      ^
main.cpp:8:17: note: void f(b<FriendP>) [with <template-parameter-2-1> = int; FriendP = rp; P = rp]
     friend void f(b<FriendP> from);
                 ^

我想知道为什么GCC声称f是过载的。所以我猜这是一个GCC bug。

哪个编译器是正确的?

友元注入在c++标准中不再存在,有关这方面的信息请参阅此。然而,由于在结构体b内部声明的友元函数"作用"于类型为"b"的形参,因此该函数是通过ADL(参数依赖查找)找到的。当这种情况发生时,声明了两个具有相同签名的不同函数,编译器会报错。

这可能就是你的意思:

template <template <typename> class P>
struct b {
    template <class, template <typename> class FriendP>
    friend void f(b<FriendP> from){};
};

,但不要在实际代码中使用它,因为正如您所看到的,"重复函数"问题很容易出现(正确使用名称空间可以在这方面有所帮助)。

代码可以在这里测试

在Effective c++

的第46项中可以找到模板友元函数的使用(以及为什么需要它们的一个很好的现实例子)的一个很好的参考。