class 体内的 C++ 友元运算符定义用作函数声明?

C++ friend operator definition inside class body serves as function declaration?

我是阅读 C++ Primer 一书的新手。它说:

A friend declaration only specifies access. It is not a general declaration of the function. If we want users of the class to be able to call a friend function, then we must also declare the function separately from the friend declaration. To make a friend visible to users of the class, we usually declare each friend (outside the class) in the same header as the class itself.

但我刚刚发现 不是 在 class 体内定义的友元运算符函数的情况。在以下代码中,找不到 f 但找到了 operator+

struct X
{
    friend void f()
    {
        // friend functions can be defined in the class
        // this does NOT serve as a declaration, even though this is already a definition
        // to use this function, another declaration is REQUIRED
    }

    friend X operator+(const X & x1, const X & x2)
    {
        // this stuff serves as declaration somehow
        return {x1.v + x2.v};
    }

    void foo()
    {
        f();                    // ERROR: no declaration for f
        X tmp = X {1} + X {2};  // CORRECT
    }

    int v;
};

有人能告诉我是什么造成了这种差异吗? 我使用的是 g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0,作为参考。 我在 Whosebug 上搜索了很多涉及朋友声明和定义的问题,但没有找到答案。对不起,如果这个问题重复了。

即使我们在 class 中定义函数,我们仍然必须在 class 本身之外提供声明以使该函数可见。即使我们只从授予 class 的友谊成员中调用朋友,声明也必须存在。这意味着在您的示例中,您应该转发声明函数f,如下所示:

//forward declare f
void f();

struct X
{
    //no ADL here since this function f has no parameters of type X. So we also need to declare this outside struct X which we did by providing forward declaration
    friend void f()
    {
        
    }

    void foo()
    {
        f();                    // WORKS NOW because of the forward declaration
        X tmp = X {1} + X {2};  //operator+ found using ADL
    }
    //other members here
};

程序输出可见here.

调用 operator+ 的原因是因为 ADL 代表 参数依赖查找 。特别是,operator+ 可以使用 ADL 找到,因为它具有 X 类型的参数。所以在这种情况下,您不需要在 struct X.

之外显式声明 operator+

区别在于operator+X为参数,然后是ADL could find名称; f一无所获,ADL也无能为力

(强调我的)

Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to ordinary name lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.