在C ++标准的最新草案(2019年3月)中,[class.friend] p.6声明(强调我):
仅当该类是非本地类([class.local]),函数名称不合格且且该函数具有名称空间范围时,才可以在该类的朋友声明中定义一个函数。 [...]
“该函数具有名称空间范围”是什么意思?
该函数没有名称空间范围的唯一情况是:
struct A
{
static void f();
struct B
{
friend void f() {};
};
};
但是 clang 和 gcc 都没有将B
内的 friend定义与{{1}内的静态方法相关联},但属于属于全局名称空间的函数。
还有其他情况我想念吗?
答案 0 :(得分:3)
我认为您实际上已经回答了自己的问题,但是没有意识到。
“该函数具有名称空间范围”意味着它是名称空间的一部分,而不是类或结构的一部分。因此,函数A :: B :: f()不存在。而且它也不引用A :: f()。相反,您定义为好友的函数实际上是函数:: f(),因为它是它所在的名称空间(全局名称空间)。
我怀疑(但没有尝试过),如果将所有这些都包装在一个命名空间中,那么您定义的f()就会成为该命名空间的一部分。例如,
namespace ns {
struct A
{
static void f();
struct B
{
friend void f() {};
};
};
}
将朋友函数定义为函数ns :: f()。
答案 1 :(得分:0)
寻找一个说不合格的函数名的friend
定义的相关规则始终是一个命名空间成员,我发现情况并非如此。 [namespace.memdef] / 3:
如果非本地类中的
friend
声明首先声明了类,函数,类模板或函数模板,则该朋友是最内层封闭的命名空间的成员。 ...如果friend
声明中的名称既不是限定值也不是 template-id ,并且声明是函数或 elaborated-type-specifier ,确定该实体先前是否已声明的查找将不考虑最内层封闭的命名空间之外的任何范围。
有问题的要求仅适用于函数定义,并排除了本地友好类或合格的朋友名称。但这留下了 template-id 作为函数名称的可能性。
因此,措辞似乎使这段代码有所不同:
struct A {
template <typename T>
static void f();
template <typename T>
struct B {
friend void f<T>() {}
};
};
此处,朋友声明中的名称为 template-id ,因此不适用有关跳过非命名空间范围的规则,并且f
实际上将功能模板命名为{{1 }}。因此,[class.friend] / 6说这是错误的格式,尽管如果A::f
声明不是一个定义,那么它会格式正确。