两个代码示例是否仅在C++23中合法,而在C++20中不合法?
关于C20与C23中默认constexpr比较运算符的合法性问题
在GCC 13.3出现回归问题后,我给程序中默认生成的太空船运算符添加constexpr时,发现不同编译器在C++20模式下处理相关代码存在差异。以下以相等比较运算符为例展示这些差异:
示例1
struct A { operator int() const; }; struct B : A { constexpr bool operator==(const B &) const = default; };
- 编译表现:该代码可在Clang和MSVC中正常编译,但开启
-pedantic-errors选项的GCC会报错:
error: call to non-'constexpr' function 'A::operator int() const' [-Winvalid-constexpr]
示例2
struct A { bool operator==(const A &) const; }; struct B : A { constexpr bool operator==(const B &) const = default; };
- 编译表现:该代码仅能在MSVC中正常编译,开启
-pedantic-errors选项的Clang也会报错:
error: defaulted definition of equality comparison operator that is declared constexpr but invokes a non-constexpr comparison function is a C23 extension [-Werror,-Wc23-default-comp-relaxed-constexpr]
问题解答
是的,这两个代码示例仅在C23中合法,在C20中均不合法,具体原因如下:
- C20标准要求:默认声明为constexpr的比较运算符,其调用的所有子操作(包括基类的转换运算符、基类的比较运算符等)必须本身是constexpr的。如果依赖的子操作不满足constexpr要求,那么默认运算符的constexpr声明就违反了C20的规则。
- C++23放宽了这一限制:默认的constexpr比较运算符允许调用非constexpr的子操作,仅要求在实际用于常量表达式计算的场景中,这些子操作能满足constexpr的要求即可(即声明阶段不强制依赖操作必须是constexpr,仅在常量上下文调用时才做校验)。
GCC和Clang开启-pedantic-errors后会严格遵循C20标准,因此触发报错;而MSVC可能默认启用了C23的扩展行为,或者对标准的实现更为宽松,所以允许编译通过。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

