安东尼·威廉姆斯(Anthony Williams)在最近的blog post中谈到了隐藏的朋友。如果我正确理解的话,主要思想是在某些情况下ADL无法找到声明为好友的函数。简单的例子:
namespace N {
struct A {
friend void foo(A) { }
};
struct B {
operator A();
};
// (*)
void bar(A) { }
}
void func() {
N::A a;
bar(a); // OK, bar is found via ADL
foo(a); // OK, foo is found via ADL
N::B b;
bar(b); // OK, bar is found via ADL
foo(b); // NOT OK, foo cannot be found
}
在博客文章的所有示例中,friend函数都是在类内部定义的。是否可以声明一个朋友功能,然后在以后的(*)
点对其进行定义,以使其保持隐藏?看来隐藏的朋友只能在类范围(或在另一个编译单元)中定义。
答案 0 :(得分:1)
隐藏的朋友需要完全内联定义,即在class定义内部。是的,如果您在其他地方定义朋友(在定义可以导致名称空间可见性的地方),它将打破仅基于ADL搜索才能发现基于隐藏朋友的限制,因此可以解决重载。
WG21 recommendations中的其他内容用于指定隐藏的朋友, 注意,隐藏的朋友是完全内联定义的,例如以下代码段:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
答案 1 :(得分:0)
隐藏的朋友可以定义,但是在那个TU中它们不是隐藏的。作为示例,请考虑以下标头:
class A {
// this is hidden friend defined inline
friend int operator+(A, int) { return 0; }
// this is hidden friend defined out of line
friend int operator+(int, A);
// not a hidden friend (see below)
friend int operator+(A, A);
};
int operator+(A, A); // this is no longer hidden friend in any TU
,然后是单独的cpp文件:
#include "a.hpp"
// This is not a hidden friend in this TU, but is in other TUs.
int A::operator+(int, A) {
return 2;
}
当您具有依赖于其他大型标头实现的操作员/ ADL自定义点时,这样做非常有用。