我建议不要在代码中使用此类“技巧”,从长远来看,这是维护噩梦,而且很难推理。几乎总是有替代方案,例如以下代码:
testStruct test = {a[++i], b[i]}
可以改为:
++i ;
testStruct test = {a[i], b[i]}
话虽如此,这两种情况都在函数调用和初始化列表中使用逗号运算符,逗号只是语法元素,仅此而已。
您的第一种情况已明确定义,但有一些警告取决于这是 C++11 还是 C++11 之前的版本。
在这两种情况下,每个逗号后面都有一个序列点,尽管 C++11 之前的版本未指定计算顺序。因此,我们可以通过以下方式查看 C++11 之前的情况:缺陷报告 430 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#430其中说:
最近的 GCC 错误报告(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633)询问有关
的有效性
int count = 23; int foo[] = { count++, count++, count++ };
这是未定义或未指定还是其他什么?
答案是(强调我的前进):
我相信标准是明确的每个初始化表达式
上面是一个完整的表达式(1.9 [介绍.执行]/12-13;另见
问题 392),因此每个后面都有一个序列点
表达式 (1.9 [intro.execution]/16)。我同意该标准确实
似乎没有规定表达式求值的顺序,
也许应该如此。有谁知道有一个编译器不会
从左到右评估表达式?
在 C++11 中,它被烘焙在C++11 标准草案 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf在部分8.4.5
段落说:
在花括号初始化列表的初始化列表中,
初始化子句,包括任何由包扩展产生的子句
(14.5.3),按照它们出现的顺序进行评估。那是,
与给定相关的每个值计算和副作用
初始化子句在每次值计算之前排序,并且
副作用与它后面的任何初始化子句关联
初始化列表的逗号分隔列表。
我坚持使用 C++11,因为它不会改变其余内容的答案,尽管排序的措辞确实有所不同,但结论是相同的。
第二种情况调用未定义的行为 http://en.wikipedia.org/wiki/Undefined_behavior因为函数参数的求值顺序是未指定的,并且它们的求值相对于彼此的顺序是不确定的。我们可以从部分看到这种未定义的行为1.9
段落15其中说:
除非另有说明,否则各个运算符的操作数的评估
和 各个表达式的子表达式是无序的。 [
注意:在计算期间多次计算的表达式中
程序的执行,无顺序和不确定顺序
其子表达式的计算不需要一致地执行
在不同的评价中。 —尾注] 的值计算
运算符的操作数在计算值之前进行排序
运算符的结果。如果标量对象的副作用是
相对于同一标量上的另一个副作用而言,未排序
对象或使用相同标量的值的值计算
对象,行为未定义.
并提供以下示例:
f(i = -1, i = -1); // the behavior is undefined