为什么我需要将此朋友函数的定义包装在名称空间中

Why do I need to enclose the definition of this friend function in a namespace?

本文关键字:包装 定义 空间 函数 朋友 为什么      更新时间:2023-10-16

在标题文件中给定一个名称空间N和类C和朋友函数f

namespace N
{
class C
{
   friend void f();
}
}

如果我在CPP文件中定义了朋友函数f

void N::f()
{
    ...
}

它不编译。如果我这样定义它:

namespace N
{
void f()
{
    ...
}
}

it do compile 。为什么?

我正在使用GCC 4.4,但是我在Coliru中尝试了一个类似的示例,用于C 14,并获得了相同的行为

从GCC 4.7的日子到现在为7.0的日子,GCC不会在封闭名称空间中引入新名称:

basic.scope.pdecl/11

朋友声明是指函数或类 最近的封闭名称空间,但它们不引入新名称 进入该名称空间。

虽然, GCC 提供了兼容性开关(-ffriend-injection将名称注入封闭名称空间)。但是,从 clang 3.1至4.0, clang 将声明注入封闭名称空间。

尽管可以通过ADL:namespace.memdef/3

找到此类功能

如果调用了朋友函数或功能模板,则其名称可能为 通过名称查找的名称查找,该查找从名称空间和 与函数参数类型相关的类 (basic.lookup.argdep)。


请参阅此相关问题,因此,所有编译器都应该尊重的是:

namespace N
{
    class C
    {
       friend void f();
    };
    void f();   //introduce the name
}
void N::f()     //define it
{ ... }

看到它活在coliru

或另一种方式:

namespace N
{
    class C{
        friend void f();
    };
}
namespace N
{
    void f()
    { ... }
}

如果符号在其定义之前在命名空间N内声明,则作为合格名称的定义应效果很好。否则它不起作用。

以下对于视觉工作室是正确的。

好:

namespace N
{
    void f();
}
void N::f() { }

不是真的可以,但是在Visual Studio中工作:

namespace N
{
class C
{
   friend void f();
}
}
void N::f() { }

不正常:

void N::f() { } // error, undefined N

不正常:

namespace N
{
}
void N::f() { } // error, f is not a member of N

,但我现在无法在不同的编译器上测试。