可以为本地类定义友元比较运算符吗?

Can friend comparison operator be defined for a local class?

提问人:Fedor 提问时间:8/20/2023 更新时间:8/20/2023 访问量:86

问:

从 C++20 开始,编译器可以为类生成默认的比较运算符,包括作为友元非成员函数,参见 cppreference.com 中的 (2)。

我遇到了在MSVC中工作的代码,该代码为函数中的本地类执行此操作:

void foo() {
    struct A;
    bool operator ==(const A&, const A&);
    struct A { 
        friend bool operator ==(const A&, const A&) = default;
    };
}

不幸的是,它在 Clang 或 GCC 中不起作用,它抱怨:

error: cannot define friend function 'operator==' in a local class definition

在线演示:https://godbolt.org/z/Ts1fer1d1

有一种方法可以使代码被 GCC 接受:

void foo() {
    struct A;
    bool operator ==(const A&, const A&);
    struct A { 
        friend bool operator ==(const A&, const A&);
    };
    bool operator ==(const A&, const A&) = default;
}

现在只打印一些模糊的警告:

warning: declaration of 'bool operator==(const foo()::A&, const foo()::A&)' has 'extern' and is initialized

但是另外两个编译器不喜欢,在线演示:https://godbolt.org/z/he1zjj46G

只要编译器存在分歧,在上面的两个示例中,哪一个是正确的?

++ 语言-律师 C++20 好友 比较-运算符

评论

1赞 Weijun Zhou 8/20/2023
对于第一部分,en.cppreference.com/w/cpp/language/friend 中的 #2 表示,只有当类是非本地的并且是定义时,才对 a 具有内联定义有效。所以 gcc 和 clang 是正确的。对于第二部分,再次是一个定义,你不能在块范围内有一个函数定义,所以我相信它也是无效的。friend...=default;...=default;

答:

3赞 Jan Schultke 8/20/2023 #1

标准对此非常明确:

当且仅当类是非本地类且函数名称是非限定的时,才能在类的友元声明中定义函数。

- [类.朋友] p6

您的第一个代码示例是在本地类中定义 a,因此它违反了本段。friend

第二个示例在块范围内定义了一个函数,该函数的格式也明显不正确:

[...]函数只能在命名空间或类范围内定义。[...]

- [dcl.fct.def.general] 第 2 页

GCC 编译它的事实是一个编译器错误,可能与 GCC 支持本地函数作为编译器扩展这一事实有关。它给出的警告是荒谬的,通常会发生在以下情况下:has 'extern' and is initialized

// <source>:1:12: warning: 'x' initialized and declared 'extern'
//     1 | extern int x = 0;
//       |            ^
extern int x = 0;

注意:我已经针对此问题提交了错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111079

评论

1赞 Language Lawyer 8/20/2023
GCC 支持将本地函数作为编译器扩展不在 C++ 中