自 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
只要编译器存在分歧,上面两个示例中哪一个是正确的?
标准对此非常明确:
当且仅当该类是非局部类且函数名未限定时,才可以在类的友元声明中定义函数。
您的第一个代码示例在本地类中定义
friend
,因此它违反了本段。
第二个示例在块作用域定义了一个函数,这显然也是格式错误的:
[...] 函数只能在命名空间或类范围内定义。 [...]
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;