You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

默认operator==下x≠x的C++程序是否合法?f()必须为true吗?

问题描述

案例一:包含A成员的结构体B

以下程序在GCC中static_assert断言失败,说明常量求值时x != x为true,其中operator==由编译器默认生成:

struct A {
    int i = 0;
    constexpr operator int() const { return i; }
    constexpr operator int&() { return ++i; }
};

struct B {
    A a;
    bool operator==(const B &) const = default;
};

constexpr bool f() {
    B x;
    return x == x;
}

static_assert( f() ); // GCC中失败

案例二:继承自A的结构体B

修改结构体B使其继承自A而非包含A成员后,程序在GCC中运行成功,但在Clang中断言失败:

struct B : A {
    bool operator==(const B &) const = default;
};

constexpr bool f() {
    B x;
    return x == x;
}

static_assert( f() ); // Clang中失败

请问:这两段程序是否均为良构程序,且f()的求值结果必须为true?


分析与结论

这两段程序均为良构程序,但根据C++标准规则,f()的求值结果并非必须为true,编译器的行为差异源于默认生成operator==时的比较逻辑实现,以及重载解析的细节处理,核心原因是A的重载转换运算符在常量求值中引入了副作用。

案例一(B包含A成员)

默认生成的B::operator==会逐成员比较x.a与x.a,此时重载解析的差异导致结果不同:

  • 右侧x.a处于const成员函数的上下文,是const A&,匹配const operator int(),返回i的初始值0。
  • 左侧x.a是非const左值,重载解析会优先选择非const的operator int&(),该转换会执行++i(此时i变为1),最终被隐式转为int值1。
  • 两者比较结果为1 == 0,即false,这是GCC断言失败的原因,且该行为符合标准规则。

案例二(B继承自A)

默认生成的B::operator==会先比较基类子对象:

  • GCC认为const B&的基类子对象是const A&,只能匹配const operator int(),两次转换都返回0,结果为true。
  • Clang在重载解析时,可能对基类子对象的const属性判断不同,触发了带副作用的operator int&(),导致两次转换后的值不同,结果为false。
  • 两种编译器的行为均未违反标准,属于规则允许的实现差异。

标准核心依据

C标准规定:默认生成的相等运算符会逐成员/基类子对象执行==比较,重载解析会根据操作数的const限定选择最优匹配的转换运算符。由于A的两个转换运算符一个无副作用、一个带++i的副作用,不同上下文的解析结果可能导致比较值不同,而这类带副作用的转换在C14及以后的常量表达式中是合法的,因此程序本身良构,但结果不固定。

内容的提问来源于stack exchange,提问作者Fedor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 00:26:05