例如对于这样的陈述:
c += 2, c -= 1
是否真的始终首先评估c + = 2,并且第二个表达式c- = 1中的c将始终是表达式c + = 2的更新值?
答案 0 :(得分:9)
是的,它由标准保证,只要该逗号是非重载的逗号运算符即可。引用n3290§5.18:
逗号运算符从左到右分组。
表达式:
赋值表达式
表达式,赋值表达式
用逗号分隔的一对表达式从左到右进行评估;左表达式被丢弃 - 价值表达(第5条) 83 。与左表达式相关的每个值计算和副作用 在每个值计算和与右表达式相关的副作用之前排序。类型 结果的值是右操作数的类型和值;结果具有相同的值类别 作为右操作数,如果右操作数是glvalue和位域,则为位字段。
以及相应的脚注:
83 但是,重载逗号运算符的调用是一个普通的函数调用;因此,对其论点的评价 表达式相对于彼此没有排序(见1.9)。
因此,对于非重载的逗号运算符,这只包含 。
函数参数之间的,
不是逗号运算符。此规则也不适用于此。
对于C ++ 03,情况类似:
逗号运算符从左到右分组。
表达式:
赋值表达式
表达式,赋值表达式
用逗号分隔的一对表达式从左到右进行计算,左表达式的值为 丢弃。左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准收敛 - sions不适用于左表达式。 左表达的所有副作用(1.9),除了 在评估正确的表达之前执行临时的破坏(12.2)。类型和 结果的值是右操作数的类型和值;如果右操作数为。
,则结果为左值
但限制是相同的:不适用于重载的逗号运算符或函数参数列表。
答案 1 :(得分:7)
是的,逗号运算符保证语句按从左到右的顺序进行计算,返回的值是最右边的计算语句。
但请注意,某些上下文中的逗号不是逗号运算符。例如,函数参数列表不保证以上内容。
答案 2 :(得分:4)
是的,在C ++中,逗号运算符是一个序列点,这些表达式将按照它们的写入顺序进行计算。请参阅当前工作草案中的5.18
:
[snip]从左到右进行评估。 [剪断]
我觉得你的问题缺乏对“副作用”的含义的一些解释。允许C ++中的每个语句都有副作用,因此重载的逗号运算符也是如此。
为什么您所写的声明在函数调用中无效?
一切都与序列点有关。在C ++和C中,禁止在两个序列点之间修改两次值。如果您的示例真正使用operator,
,则每个自我赋值都在其自己的序列点内。如果您像foo(c += 2, c -= 2)
那样使用它,则评估顺序是不确定的。我实际上不确定第二种情况是否是未定义的行为,因为我不知道参数列表是一个还是多个序列点。我应该问这个问题。
答案 3 :(得分:1)
应始终从左到右进行评估,因为这是逗号运算符的定义: Link
答案 4 :(得分:0)
你有两个问题。
第一个问题:“逗号操作员是否没有副作用?”
答案是否定的。逗号运算符自然地有助于编写具有副作用的表达式,并且故意编写具有副作用的表达式是操作员通常使用的表达式。例如,在while (cin >> str, str != "exit")
中输入流的状态发生了变化,这是一种有意的副作用。
但也许你并不是指计算机科学意义上的副作用,而是在某种临时意义上。
你的第二个问题:“例如对于这样的陈述:c += 2, c -= 1
c + = 2总是首先被评估,而第二个表达式c- = 1中的c将始终是表达式c的更新值+ = 2?“
对于语句或表达式,答案是肯定的,除非逗号运算符过载(非常不寻常)。但是,c += 2, c -= 1
之类的序列也可以出现在参数列表中,在这种情况下,您所获得的不是表达式,逗号不是序列运算符,并且未定义评估顺序。在foo(c += 2, c -= 1)
中,逗号不是逗号运算符,但在foo((c += 2, c -= 1))
中它是,所以在函数调用中注意括号可能会付出代价。