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

2022-01-14 00:00:00 namespaces c++ friend-function

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

Consider a class inside a namespace. The definition of the class declares a friend function.

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

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

This should, based on what I know, declare baz() as a member of the innermost enclosing namespace, i.e. Foo.

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

Therefore, I expected the following definition for baz() to be correct:

void Foo::baz() { }

但是,GCC (4.7) 给了我一个错误.

However, GCC (4.7) gives me an error.

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

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

Several solutions seem to work:

  • 在类外声明 baz().

namespace Foo
{
    void baz();

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

  • 在命名空间内定义baz().

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

  • 使用 -ffriend-injection 标志编译,消除错误.

  • Compile with the -ffriend-injection flag, which eliminates the error.

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

    These solutions seem to be inconsistent with the general rules of declaration/definition in C++ I know.

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

    Why do I have to declare baz() twice?
    Why is the definition otherwise only legal inside a namespace, and illegal with the scope resolution operator?
    Why does the flag eliminate the error?

    推荐答案

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

    Why do I have to declare baz() twice?

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

    Because the friend declaration doesn't provide a usable declaration of the function in the namespace. It declares that, if that function is declared in that namespace, it will be a friend; and if you were to define a friend function inside a class, then it would be available via argument-dependent lookup (but not otherwise) as if it were declared in the namespace.

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

    Why is the definition otherwise only legal inside a namespace, and illegal with the scope resolution operator?

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

    Because it hasn't been (properly) declared in the namespace, and a function can only be defined outside its namespace (with scope resolution) if it has been declared.

    为什么flag会消除错误?

    Why does the flag eliminate the error?

    因为标志导致友元声明充当命名空间中的声明.这是为了与 C++ 的古代方言(显然还有一些现代编译器)兼容,其中这是标准行为.

    Because the flag causes the friend declaration to act as a declaration in the namespace. This is for compatibility with ancient dialects of C++ (and, apparently, some modern compilers) in which this was the standard behaviour.

  • 相关文章