在头文件中给定一个名为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时尝试了一个类似的例子并且得到了相同的行为
答案 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没有在封闭的命名空间中引入新名称,如下所述:
朋友声明是指作为其成员的函数或类 最近的封闭命名空间,但它们不引入新名称 进入该命名空间。
虽然 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
{ ... }
或者另一种方式:
namespace N
{
class C{
friend void f();
};
}
namespace N
{
void f()
{ ... }
}