来自 andyli 的提问:
#include <cstdio>
#include <vector>
struct T {
int x;
};
T& f() {
puts("f");
static T x{};
return x;
}
T& g() {
puts("g");
static T x{};
return x;
}
int main() {
f() = g();
f().operator=(g());
}
对于以上代码的运行结果有疑惑:
g
f
g
f
下意识认为应该是先计算 =
左边,理所应当的认为应该先打印 f,然后 g。
然而并非如此,查看求值顺序规则。
每个简单赋值表达式 E1 = E2 和每个复合赋值表达式 E1 @= E2 中,E2 的每个值计算和副作用都按顺序早于 E1 的每个值计算和副作用。
但是这依旧没办法解释 f().operator=(g())
的运行结果;以及 f() = g()
这个表达式中使用到的 =
明显不是内建运算符,它是类默认生成的重载运算符。
这个可以根据规定:
用运算符写法进行调用时,每个重载的运算符都会遵循它所重载的内建运算符的定序规则。
f() = g();
可以解释了,但是 f().operator=(g())
不行,根据规定:
函数调用表达式中,指名函数的表达式按顺序早于每个参数表达式和每个默认实参。
- 这应当算作 编译器 bug
实测 gcc msvc 都是那个结果,但是 clang 不同。
g
f
f
g
只有 clang 是遵守了规定的,合理的结果。第一个表达式按照了内建赋值运算符的求值规则,第二个表达式按照了函数调用表达式的求值规则。