命名空间内的Friend函数声明/定义

时间:2013-05-23 15:35:47

标签: c++ namespaces friend-function

考虑命名空间内的一个类。该类的定义声明了一个友元函数。

namespace Foo
{
    class Bar
    {
        friend void baz();
    };
}

根据我所知,这应该将baz()声明为最里面的封闭命名空间的成员,即Foo

因此,我希望baz()的以下定义是正确的:

void Foo::baz() { }

然而,GCC(4.7)给我一个错误。

error: ‘void Foo::baz()’ should have been declared inside ‘Foo’

有几种解决方案似乎有效:

  • 在课堂外声明baz()

    namespace Foo
    {
        void baz();
    
        class Bar
        {
            friend void baz();
        };
    }
    
  • 在命名空间内定义baz()

    namespace Foo
    {
        class Bar
        {
            friend void baz();
        };
    }
    ...
    namespace Foo
    {
        void baz() { }
    }
    
  • 使用-ffriend-injection标志进行编译,从而消除错误。

这些解决方案似乎与我所知的C ++中的声明/定义的一般规则不一致。

为什么我必须两次声明baz()? 为什么定义在命名空间内只是合法的,而且使用范围解析运算符是非法的? 为什么标志会消除错误?

2 个答案:

答案 0 :(得分:4)

  

为什么我必须两次声明baz()?

因为friend声明没有在命名空间中提供函数的可用声明。它声明,如果该函数在该命名空间中声明,它将是一个朋友;如果你在一个类中定义一个友元函数,那么它将通过依赖于参数的查找(但不是其他方式)可用,就好像它是在命名空间中声明一样。

  

为什么定义在命名空间内只是合法的,而且使用范围解析运算符是非法的?

因为它没有在命名空间中(正确地)声明,并且只有声明了函数才能在其命名空间之外定义(使用范围解析)。

  

为什么标志会消除错误?

因为该标志导致friend声明在命名空间中充当声明。这是为了兼容古老的C ++方言(显然,一些现代编译器),这是标准的行为。

答案 1 :(得分:1)

第一段代码应编译:

namespace A {
   struct B {
      friend void foo();
   };
}
void A::foo() {}

虽然除非您还在命名空间级别提供声明,否则不能使用特定功能。原因是友元声明只能通过Argument Dependent Lookup(ADL)看到,但foo不依赖于A::B,因此编译器永远不会查看该类型。