C++三目运算符

8
我遇到了一些有趣的事情,我之前并没有意识到三元运算符(至少在 Visual C++ 98-2010 中)的一些特点。正如 http://msdn.microsoft.com/en-us/library/e4213hs1(VS.71).aspx 所指出的那样,如果表达式和条件表达式都是左值,则结果也是一个左值。
当然,在 c/c++ 中,你通常会写出这样的代码:
int value = (x == 1) ? 1 : 0;
并且从不关心 r-value/l-value 的问题,在这种情况下,1 和 0 都无法转换为左值。
然而,考虑以下代码:
int value = (x == 1) ? y : z;
y 和 z 都是左值,它们或者更准确地说,其中一个是三元运算符的实际结果(而不是其存储值),这可能并不明显(至少我从未深入思考过这个问题)。
但是,这导致我们能够编写以下代码:
(x == 1 ? y : z) = 99;
如果 x == 1,则将 99 赋给 y;否则将 99 赋给 z。
我从未在任何地方看到过这种描述,在所有我读过的关于使用(或通常是否使用)三元运算符的讨论中都没有提到过。
当然,只有在表达式和条件表达式都是左值时才能使用此方法,例如:
(x == 1 ? 0 : z) = 99;
无法编译,因为 0 是一个 r-value,编译器会提示错误。
而且只有在包含括号时才能使用:
x == 1 ? y : z = 99;
这完全是另一回事,如果 (x != 1),则将 99 分配给 z,两边仍然是左值,所以会出现像 (x == 1 ? y : z = 99) = 100 这样的问题(它根据 x == 1 的真假将 100 分配给 y 或 z,在 x==1 为 false 时覆盖了 z=99 赋值)。
这引出了我的问题:
A)这是实际的 c++ 标准的一部分(看起来应该是),而不仅仅是 Microsoft 的东西吗?我已经搜索过但尚未找到相关信息。
B)如果这是众所周知的,并且我一直生活在岩石下面?我从未见过它在任何我记得的代码中使用过,也从未在讨论三元运算符时提到过它。
C)我需要更经常地外出吗?

1
A) 是的,根据我的模糊记忆。 B) 是的,那里还有更多的空间吗? C) 那会有帮助吗?对于什么? - peterchen
当无知是幸福时,聪明反被视为愚蠢。 - Brian Hooper
1
你之前没看到它是因为它很难读。难以阅读的代码对可维护性不利。 - Martin York
3个回答

10

A) 是的,这是标准的一部分。

B) 尽管可能在SO上已经被广泛意识到,但并不为人所知。这就是为什么它被选为C++ #1隐藏功能的原因:Hidden Features of C++?

C) 没有评论 :)

个人建议避免使用此功能。它比使用if/else语句要难以理解得多,并且显然不是每个人都知道。尽管我自己发出了警告,但我曾在一个个人项目中尝试使用过它,结果错过了括号并浪费了30分钟来查找错误。


希望在发帖之前我能遇到这个...我确实查看了,但显然错过了它。 - Ruddy

3

A. 是的。根据§[expr.cond]/4:

如果第二个和第三个操作数都是左值并且类型相同,则结果为该类型并且是左值...

(请注意,在C语言中不是这样的。在C99标准中明确说明,脚注93中写道,“条件表达式不产生左值。”)

B. 我认为它的使用相当晦涩,因此并没有被广泛使用。更常见的是看到:

if (x == 1)
  y = 99;
else
  z = 99;

值得一提的是:我已经验证了在Visual 2010中符合脚注93,也就是说当你尝试在.c(纯C)文件中编译(x == 1 ? y : z) = 100;时,你会得到一个编译错误("...左操作数必须是l-value")。 - Ruddy

2
你从未见过它被使用,因为这种用法不如最常见的那种直观易读。我也从未在生产代码中看到过这种用法,希望我永远不会看到。
请记住Herb Sutter和Andrei Alexandrescu的C++编程规范,第6条规则是:“正确性、简洁性和清晰度优先”。

我肯定不是在倡导它的使用 - 目前只是一种好奇心。 - Ruddy
@Ruddy:我只是在回答B。我不确定A(虽然我99%确定它是正确的)或C :) - Daniel Daranas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接