为什么我需要在命名空间中包含此友元函数的定义?

时间:2017-02-17 09:18:20

标签: c++

在头文件中给定一个名为N的名称空间C和一个朋友函数f

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

如果我在cpp文件中定义友元函数f,如下所示:

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

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

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

确实编译。为什么呢?

我正在使用gcc 4.4,但我在Coliru编译C ++ 14时尝试了一个类似的例子并且得到了相同的行为

2 个答案:

答案 0 :(得分:1)

如果符号在定义之前在名称空间N内声明,则定义为限定名称应该可以正常工作。否则它无法正常工作。

视觉工作室的确如此。

确定:

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

不太好,但在视觉工作室工作:

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

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

答案 1 :(得分:1)

从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)。

请参阅此related question,那么,所有编译器应该尊重的是:

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

    void f();   //introduce the name
}

void N::f()     //define it
{ ... }

Live On Coliru

或者另一种方式:

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

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