隐藏的朋友:声明和定义
Hidden friends: declarations and definitions
安东尼·威廉姆斯在他最近的 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
}
在博客 post 的所有示例中,友元函数都定义在 classes 中。是否可以声明一个友元函数,然后在 (*)
点定义它,使其 保持 隐藏?看起来隐藏的朋友只能在 class 范围内(或在另一个编译单元中)定义。
隐藏的朋友需要完全内联定义,即在 class 的定义内部。是的,如果您在其他地方定义朋友,定义可能导致名称空间可见性,它将打破基于隐藏朋友的限制,这些隐藏朋友只能通过 ADL 搜索找到匹配项,因此成为重载解析的候选者。
在 WG21 recommendations 中还有更多关于指定隐藏好友的内容,
注意到隐藏的朋友是完全内联定义的,就像这个片段:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
隐藏的朋友可以定义出线,但他们在那个TU里不隐藏。例如,考虑这个 header:
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;
}
当您的 operators/ADL 自定义点依赖于其他大型 header 的实现时,这样做很有用。
安东尼·威廉姆斯在他最近的 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
}
在博客 post 的所有示例中,友元函数都定义在 classes 中。是否可以声明一个友元函数,然后在 (*)
点定义它,使其 保持 隐藏?看起来隐藏的朋友只能在 class 范围内(或在另一个编译单元中)定义。
隐藏的朋友需要完全内联定义,即在 class 的定义内部。是的,如果您在其他地方定义朋友,定义可能导致名称空间可见性,它将打破基于隐藏朋友的限制,这些隐藏朋友只能通过 ADL 搜索找到匹配项,因此成为重载解析的候选者。
在 WG21 recommendations 中还有更多关于指定隐藏好友的内容, 注意到隐藏的朋友是完全内联定义的,就像这个片段:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
隐藏的朋友可以定义出线,但他们在那个TU里不隐藏。例如,考虑这个 header:
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;
}
当您的 operators/ADL 自定义点依赖于其他大型 header 的实现时,这样做很有用。