朋友函数的C ++内联定义

问题描述 投票:6回答:2

在当前的C ++标准草案(2019年3月)中,[class.friend] p.6声明(强调我的):

当且仅当该类是非本地类([class.local]),函数名称是非限定的,并且该函数具有命名空间范围时,才能在类的友元声明中定义函数。 [...]

“函数具有命名空间范围”是什么意思?

我能想出的唯一一个函数没有命名空间范围的情况如下:

struct A
{
    static void f();

    struct B
    {
        friend void f() {}; 
    }; 
};

但是,clang和gcc都不会将B中的朋友定义与A中的静态方法相关联,而是与属于全局命名空间的函数相关联。

我还缺少其他情况吗?

c++ language-lawyer friend
2个回答
3
投票

我认为你已经回答了自己的问题,但没有意识到。

“函数具有命名空间范围”意味着它是命名空间的一部分,而不是类或结构的一部分。所以函数A :: B :: f()不存在。并且它也没有引用A :: f()。相反,您定义为朋友的函数实际上是函数:: f(),因为它是它所驻留的命名空间(全局命名空间)。

我怀疑(但尚未尝试过),如果你将所有这些包装在一个命名空间中,那么你定义的f()将是该命名空间的一部分。所以,例如,

namespace ns {
    struct A
    {
        static void f();

        struct B
        {
            friend void f() {}; 
        }; 
    };
}

将friend函数定义为函数ns :: f()。


0
投票

寻找相关规则,说明一个非限定函数名称的friend定义始终是命名空间成员,我发现情况并非如此。 [namespace.memdef] / 3:

如果非本地类中的friend声明首先声明了类,函数,类模板或函数模板,则该朋友是最内层封闭命名空间的成员。 ...如果friend声明中的名称既不是限定的也不是模板ID,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑除此之外的任何作用域。最里面的封闭命名空间。

有问题的要求仅适用于函数定义,并排除本地友好类或合格的朋友名称。但这留下了模板ID作为函数名称的可能性。

所以措辞似乎对这段代码产生了影响:

struct A {
    template <typename T>
    static void f();

    template <typename T>
    struct B {
        friend void f<T>() {}
    };
};

在这里,friend声明中的名称是template-id,因此关于跳过非命名空间作用域的规则不适用,f确实命名了函数模板A::f。所以[class.friend] / 6表示这是不正确的,但如果friend声明不是一个定义,它将是良好的形式。

© www.soinside.com 2019 - 2024. All rights reserved.