为什么不能重载三元运算符'?''?
我经常使用三元运算符来合并if语句,并且很好奇为什么语言设计者选择禁止此运算符过载。我在C++ Operator Overloading寻找了解释原因的解释,但没有找到解释为什么这是不可能的。脚注提供的唯一信息是它不能超载。
我最初的猜测是,重载运算符几乎总是违反上面链接中给出的第一或第二原则。重载的含义很少是明显的或明显的,或者它将偏离其原始的已知语义。
所以我的问题更多的是为什么这不可能而不是如何,因为我知道它无法完成。
答案 0 :(得分:17)
我认为当时的主要原因似乎并不值得
为该运算符发明新语法的努力。
没有令牌?:
,因此您必须创建一些令牌
专门针对它的语法规则。 (目前的语法规则
operator
后跟一个运算符,它是一个运算符
令牌。)
我们已经(从经验中)了解到使用运算符重载
更合理的是,我们显然不应该这样做
允许重载&&
和||
其他答复指出的原因,可能不是
运算符逗号(因为重载版本不会有
用户期望的序列点)。所以动机
支持它甚至比原来还要少。
答案 1 :(得分:16)
如果你可以覆盖三元运算符,你必须写这样的东西:
xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );
要调用覆盖,编译器必须计算trueVal
和falseVal
的值。这不是内置三元运算符的工作方式 - 它只计算其中一个值,这就是为什么你可以编写如下内容的原因:
return p == NULL ? 23 : p->value;
不用担心通过NULL指针进行间接。
答案 2 :(得分:6)
三元运算符的一个原则是仅基于条件表达式的真或假来评估真/假表达式。
cond ? expr1 : expr2
在此示例中,expr1
仅在cond
为真时进行评估,而expr2
仅在cond
为假时进行评估。牢记这一点让我们看一下三元重载的签名是什么样的(为了简单起见,使用固定类型而不是模板)
Result operator?(const Result& left, const Result& right) {
...
}
这个签名根本不合法,因为它违反了我描述的确切语义。为了调用此方法,语言必须同时评估expr1
和expr2
,因此不再对其进行有条件的评估。为了支持三元运算符,需要
expr1
还是expr2
修改强>
有些人可能认为在这种情况下缺少短路是好的。原因是C ++已经允许您使用||
和&&
Result operator&&(const Result& left, const Result& right) {
...
}
尽管我仍然发现这种行为令人困惑,即使对于C ++也是如此。
答案 3 :(得分:1)
出于同样的原因,为什么你真的不应该(尽管你可以)重载&&
或||
运算符 - 这样做会禁止那些运算符的短路(只评估必要的部分而不是一切),这可能导致严重的并发症。
答案 4 :(得分:1)
简短而准确的回答只是“因为那是Bjarne的决定。”
虽然关于应该评估哪些操作数的论据以及以什么顺序给出技术上准确描述发生的事情的论点,但它们很少(没有,真的)解释为什么这个特定的算子不能被重载。
特别是,相同的基本论点同样适用于operator &&
和operator||
等其他运算符。在每个运算符的内置版本中,左操作数被计算,然后当且仅当它为1
生成&&
或0
生成||
时,评估右操作数。同样,(内置)逗号运算符计算其左操作数,然后计算其右操作数。
在任何这些运算符的重载版本中,两个操作数总是被评估(以未指定的顺序)。因此,在这方面,它们基本上与过载的三元运算符相同。他们都对所评估的操作数以及按什么顺序失去了相同的保证。
至于Bjarne做出这个决定的原因:我可以看到一些可能性。一个是虽然它在技术上是一个运算符,但三元运算符主要用于流控制,因此重载它更像是重载if
或while
而不是重载大多数其他运算符。
另一种可能性是它在语法上很难看,要求解析器处理类似operator?:
的东西,这需要将?:
定义为令牌等等 - 所有这些都需要相当严重的更改C语法。至少在我看来,这个论点似乎相当弱,因为C ++已经需要一个多比C更复杂的解析器,并且这个改变实际上 小于其他许多已经做出的改变。
也许所有人最强烈的争论仅仅是它似乎没有取得多大成就。由于它主要用于流控制,因此改变它对某些类型的操作数所做的工作不太可能完成任何非常有用的工作。