Why does the ternary operator with commas evaluate only one expression in the true case?
我目前正在学习使用C ++ Primer一书的C ++,本书的其中一个练习是:
Explain what the following expression does:
someValue ? ++x, ++y : --x, --y
我们知道什么?我们知道三元运算符的优先级高于逗号运算符。使用二元运算符这很容易理解,但是对于三元运算符,我有点挣扎。使用二元运算符"具有更高的优先级"意味着我们可以使用具有更高优先级的表达式周围的括号,并且它不会更改执行。
对于三元运算符,我会这样做:
1 | (someValue ? ++x, ++y : --x, --y) |
有效地产生相同的代码,这无法帮助我理解编译器如何对代码进行分组。
但是,通过使用C ++编译器测试,我知道表达式编译,我不知道
然后我以两种方式执行程序:
1 2 3 4 5 6 7 8 9 10 11 12 | #include <iostream> int main() { bool someValue = true; int x = 10, y = 10; someValue ? ++x, ++y : --x, --y; std::cout << x <<"" << y << std::endl; return 0; } |
结果是:
1 | 11 10 |
另一方面,用
1 | 9 9 |
为什么C ++编译器会生成三元运算符的真分支只递增
我甚至把括号括在真正的分支周围,就像这样:
1 | someValue ? (++x, ++y) : --x, --y; |
但它仍然导致
正如@Rakete在他们出色的回答中所说,这很棘手。我想补充一点。
三元运算符必须具有以下形式:
logical-or-expression
? expression: assignment-expression
所以我们有以下映射:
-
someValue :logical-or-expression -
++x, ++y :表达 -
???赋值表达式
--x, --y 还是仅--x ?
实际上它只是
这导致三元(条件)表达式部分看起来像这样:
1 | someValue?++x,++y:--x |
为了可读性,可能有助于将
并按此顺序评估:
然后将此表达式视为逗号运算符的左子表达式,右子表达式为
1 | (someValue?(++x,++y):--x), --y; |
这意味着左侧是一个丢弃值表达式,意味着它被明确地评估,但是然后我们评估右侧并返回它。
那么当
要"修复"该行为,可以将
1 | someValue?++x,++y:(--x, --y); |
*这是一个相当有趣的长链,它将赋值表达式连接回主表达式:
assignment-expression ---(可以包含) - > conditional-expression - > logical-or-expression - > logical-and-expression - > inclusive-or-expression - > exclusive-or-expression - - > and-expression - > equality-expression - > relational-expression - > shift-expression - > additive-expression - > multiplicative-expression - > pm-expression - > cast-expression - > unary-expression - > postfix-expression - > primary-expression
哇,这太棘手了。
编译器将您的表达式视为:
1 | (someValue ? (++x, ++y) : --x), --y; |
三元运算符需要一个
现在,为什么你得到那个输出可能更有意义。如果
如果
Why would the C++ compiler generate code that for the true-branch of the ternary operator only increments
x
你误解了发生了什么。真分支增加
以下是这种情况:由于条件运算符的优先级高于C ++中的逗号运算符,编译器将按如下方式解析表达式:
1 2 | (someValue ? ++x, ++y : --x), (--y); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ |
注意逗号后面的"孤立"
I even went as far as putting parentheses around the true-branch like this:
1 someValue ? (++x, ++y) : --x, --y;
你是在正确的道路上,但你把一个错误的分支括起来:你可以通过括号化else分支来解决这个问题,如下所示:
1 | someValue ? ++x, ++y : (--x, --y); |
演示(打印11 11)
你的问题是三元表达式的优先级并不高于逗号。实际上,C ++不能简单地通过优先级来准确描述 - 它正是三元运算符和逗号分解之间的交互。
1 | a ? b++, c++ : d++ |
被视为:
1 | a ? (b++, c++) : d++ |
(逗号的行为就像它具有更高的优先级)。另一方面,
1 | a ? b++ : c++, d++ |
被视为:
1 | (a ? b++ : c++), d++ |
并且三元运算符具有更高的优先级。
在答案中被忽略的一点(虽然涉及到注释)是条件运算符总是在实际代码中用于(设计意图?)作为将两个值中的一个赋值给变量的快捷方式。
因此,更大的背景是:
1 | whatIreallyWanted = someValue ? ++x, ++y : --x, --y; |
这是荒谬的,所以犯罪是多方面的:
- 该语言允许在作业中产生荒谬的副作用。
- 编译器没有警告你,你在做奇怪的事情。
- 这本书似乎专注于"技巧"问题。人们只能希望后面的答案是"这个表达的作用取决于一个人为的例子中的奇怪的边缘情况,以产生没人想要的副作用。永远不要这样做。"