C++17:连续赋值触发GCC警告,左值value computation是否涉对象值?
i = i = Int{1};的-Wsequence-point警告合理性解析 核心问题回顾
用GCC 5-12编译代码i = i = Int{1};(等价于i.operator=(i.operator=(Int{1}));)时会触发-Wsequence-point警告。依据C++17标准[intro.execution]/17:
同一内存位置的未序贯side effect,或side effect与使用对象值的value computation未序贯时,行为未定义(UB)。
用户的疑问聚焦于:int&类型glvalue的value computation是否属于“使用对象值的value computation”?这直接决定该代码是否真的违反UB规则。
关键概念拆解
glvalue的value computation本质
glvalue的value computation仅负责确定对象的内存标识(即定位到对象所在的内存地址),全程不需要读取对象的当前值。以代码中外层operator=的左操作数i为例,它是一个glvalue,其value computation只是找到i对应的内存位置,完全不涉及读取i的现有值。C++17的序贯规则适配
代码中内层operator=(Int{1})的side effect是给i赋值,该操作的返回值是指向i的int&。外层operator=的左操作数i的value computation,与内层赋值的side effect之间,虽然没有严格的序贯关系,但由于前者没有使用i的值,仅做地址定位,完全符合C++17的规则——不存在“未序贯的side effect与值使用”的冲突。
警告原因:GCC的规则滞后
-Wsequence-point警告最初是为C11之前的旧序列点规则设计的,而C17重新定义了更宽松的“序贯”逻辑。GCC的该警告模块没有完全适配C++17的更新,导致对一些合法代码误触发警告。
结论
int& glvalue的value computation不属于“使用对象值的value computation”,因此i = i = Int{1};在C++17中是合法代码,不存在未定义行为,GCC的该警告属于过时的误报。
内容的提问来源于stack exchange,提问作者Lukas Barth

