能否为局部类定义友元比较运算符?C++20编译器分歧解析
C++20局部类默认比较运算符的标准合规性问题
自C20起,编译器可为类生成默认比较运算符,包括以友元非成员函数的形式实现。针对局部类中使用该特性的两种写法,结合C标准分析如下:
第一种写法(仅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
标准合规性分析:
根据C标准[class.friend]条款规定:只有非局部类的友元声明中才能定义函数,局部类不允许在友元声明里直接定义函数(包括使用=default的默认函数)。此处将operator==的默认定义写在局部类的友元声明中,属于在局部类内定义友元函数,违反了标准要求,因此这种写法不符合C标准,MSVC的支持属于非标准扩展。
第二种写法(仅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; }
GCC给出警告:
warning: declaration of 'bool operator==(const foo()::A&, const foo()::A&)' has 'extern' and is initialized
MSVC和Clang直接拒绝编译。
标准合规性分析:
C标准明确禁止函数嵌套定义,即不能在一个函数内部定义另一个非成员函数。此处在foo()函数内定义全局作用域的operator==(即便其参数是局部类类型),本质上属于函数嵌套定义,违反了标准的核心规则,因此这种写法也不符合C标准。GCC的接受属于非标准行为,其警告也侧面反映了该写法的不合理性。
结论
上述两种写法均不符合C标准。当前C标准下,若需为局部类实现默认比较,建议直接将operator==声明为类的成员函数并使用=default,这种写法符合标准且能被所有主流编译器正确处理:
void foo() { struct A { bool operator==(const A&) const = default; }; }
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

