成员初始化中表达式的评估是否相互排序?

ybu*_*ill 4 c++ constructor member language-lawyer

具体来说,我说:

struct X { X(int i) { cout << i; } };
int f() { cout << 'f'; return 0; }
int g() { cout << 'g'; return 1; }

struct Z {
    Z() : a(f()), b(g()) {}
    X a, b;
};

int main() { Z z; cout << '\n'; }
Run Code Online (Sandbox Code Playgroud)

我知道成员的构造函数保证按照它们在其中定义的顺序被调用struct,因此0将在之前打印1.但是如何评价他们的论点呢?它保证是:

f0g1
Run Code Online (Sandbox Code Playgroud)

?也许,

fg01
Run Code Online (Sandbox Code Playgroud)

gf01
Run Code Online (Sandbox Code Playgroud)

也是有效的输出?

参考该标准是值得赞赏的.

Sha*_*our 5

C++ 11草案标准中,每个成员初始化程序都是一个完整表达式,因此所有副作用必须在评估下一个之前生效.

712.6.2 初始化基础和成员说:

[...]每个mem-initializer执行的初始化构成一个完整表达式.mem-initializer中的任何表达式都将作为执行初始化的完整表达式的一部分进行评估.[...]

1.9 程序执行14段说:

在与要评估的下一个全表达式相关联的每个值计算和副作用之前,对与全表达式相关联的每个值计算和副作用进行排序.

部分的相关语法12.6.2如下:

ctor-initializer:
   : mem-initializer-list
mem-initializer-list:
   mem-initializer ...opt
   mem-initializer , mem-initializer-list ...opt
[...]
Run Code Online (Sandbox Code Playgroud)

C++ 11上,每个mem-initializer上的完整表达式的相同措辞都不存在,至少在1804年最早的草案标准中没有.但据我可以告诉我用同样的逻辑是初始化列表内的同一变量的多个突变未定义行为预先C++ 11适用于这种情况下,所以我们应该期望相同的行为预C++ 11的好.