朋友定义函数的命名空间是什么?

4

如果我在一个类中定义了一个友元函数,那么这个函数的命名空间是什么?

namespace A{namespace B{
    struct S{
        friend void f(S const&){};
    };
}}

int main(){
    A::B::S s{};
    f(s); // ok
    ::f(s); // not ok, no f in global namespace
    A::B::f(s); // no f in A::B
    A::B::S::f(s); // not ok, no f in A::B::S
}

它是否有命名空间? 它是否有必要拥有命名空间?

如果我想要消除常用习语中的歧义呢?

using std::swap;
swap(a, b);

我是否被迫在类外定义它并将其声明为友元?


你可以在友元声明之前在某个命名空间中声明该函数。 - Walter
普通表达式 f(s) 之所以有效,是因为 参数依赖查找。该函数在 A::B::S 的作用域中声明,但它不是类的成员。 - Some programmer dude
@Someprogrammerdude 这不是意味着 fA::B 中(与其参数相同的命名空间)吗? - Walter
不必进行歧义消除,因为ADL已经实现了此功能。这就是该习惯用法的全部意义:为了使std::swap在查找时被考虑(对于不属于std的类型),您必须将其带入本地范围。 - Walter
1
@Some programmer dude:该函数实际上在A::B中,而不是在A::B::S中。它只是对于普通名称查找不可见。 - AnT stands with Russia
3个回答

6

友元声明指的是从最近的封闭命名空间中引用函数。然而,它不会将该函数的名称引入命名空间中。

9.3.1.2 命名空间成员定义
3 如果非局部类中的友元声明首先声明了一个类、函数、类模板或函数模板,则该友元是最内层封闭命名空间的成员。友元声明本身不会使名称对未限定查找或限定查找可见。

http://eel.is/c++draft/namespace.memdef#3

所以,在您的情况下,A::B::f 是一个友元。然而,名称 fA::B 中尚不存在。在提供 A::Bf 的显式声明之前,您将无法将其称为 A::B::f
名称查找能够通过称为参数相关查找(ADL)的特殊机制在未限定的f(s)调用中找到f。 ADL是唯一能“看到”您的函数的机制。

术语不应该是“introduce”,而应该是“inject”吗? - Walter
@Walter:术语“inject”通常用于发生某种名称注入的情况。在这种情况下,它并没有发生。我认为对于某些并未发生的事情使用哪个术语并不重要))) - AnT stands with Russia

4

这个函数在A::B中,但只能通过ADL或Koenig Lookup找到它。

唯一的命名方式是在类定义之外引入它。

是的,这很奇怪。

namespace A{namespace B{
  inline void f(S const&);
  struct S{
    friend void f(S const&){};
  };
}}

现在,A::B::f 代表 f
这种技术是我用来介绍运算符和其他自定义点的。它还允许在非模板类的模板类上创建每个模板实例函数。
template<class T>
struct foo {
  friend void not_a_template( T ){}
};
template<class T>
void is_a_template(T){}

1
这很有趣,这意味着如果我定义一个像这样的函数,它将必须至少有一个与封闭类型相同的参数。否则它将永远不会在命名空间外被找到。更奇怪的是。 - alfC

1

是的,您可以在类外定义函数并将其设置为某个类的友元函数。它是完全独立的函数,但您允许它访问特定的类。

在命名空间中首次声明的每个名称都是该命名空间的成员。如果非局部类中的友元声明首次声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。


@Walter 它确实A::B的成员,但由于在A::B::S的词法作用域之外没有f的声明,因此只能通过未限定的查找调用f(并通过ADL找到)。 - David G
1
@0x499602D2 这听起来对我来说像是一个答案。请发布它。 - Walter
我相信 @0x - PStarczewski
我相信@0x499602D2试图以更明智的方式表达我所尝试的内容。我不是英语母语者,所以请原谅我的错误。C++具有块词法作用域,因此您必须在那里定义它。当您声明一个未经限定的友元函数时,它会命名最近的命名空间范围内的函数。在友元函数之前未声明的情况下,声明在正常查找中不可见。抱歉,我是新手,还不能正确添加评论。 - PStarczewski
如果有什么不容易理解的,请告诉我,我会尽力更好地解释我的陈述和思维方式。 - PStarczewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接