为什么不能使三元运算符超载?

Pau*_*ton 19 c++ operator-overloading operators ternary-operator visual-c++

为什么不能使三元运算符超载?:'?

我经常使用三元运算符来合并if语句,并且很好奇为什么语言设计者选择禁止此运算符过载.我找到了解释为什么在C++运算符重载但未找到描述为什么这是不可能的解释.脚注提供的唯一信息是它不能超载.

我最初的猜测是,重载运算符几乎总是违反上面链接中给出的第一或第二原则.重载的含义很少是明显的或明显的,或者它将偏离其原始的已知语义.

所以我的问题更多的是为什么这不可能而不是如何,因为我知道它无法完成.

Mar*_*low 18

如果你可以覆盖三元运算符,你必须写这样的东西:

xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );
Run Code Online (Sandbox Code Playgroud)

打电话给你的覆盖,编译器必须能够计算两者的价值trueValfalseVal.这不是内置三元运算符的工作方式 - 它只计算其中一个值,这就是为什么你可以编写如下内容的原因:

return p == NULL ? 23 : p->value;
Run Code Online (Sandbox Code Playgroud)

无需担心通过NULL指针间接.

  • 同样的推理适用于`_&`和`||`,你_can_重载. (17认同)
  • @JamesKanze和*是一个可怕的决定*. (9认同)
  • @JamesKanze当然.后见之明是件好事.我个人很喜欢它,如果C++ 11禁用运算符`&&`,`||`和`,`的重载,默认情况下,**除非**程序员包含一些特殊的标题(或传递一个特殊的编译器开关) ).我认为一种语言不能让过去的错误永久地在向后兼容的祭坛上向前传播. (2认同)
  • @NikBougalis标准的作用_isn't_促进良好实践(事实上,在许多情况下,它恰恰相反); 它是标准化现有的做法.今天没有什么可以阻止编译器警告这种做法.(但它不是黑白的.标准可以弃用它们,例如鼓励编译器警告.) (2认同)

Jam*_*nze 17

我认为当时的主要原因似乎不值得为该运算符发明新语法.没有令牌?:,所以你必须为它创建一些特殊的语法规则.(当前的语法规则operator后跟一个运算符,它是一个令牌.)

正如我们已经(从经验中)学到的更合理地使用运算符重载,很明显我们确实不应该允许重载&&||其他任何响应指出的原因,也可能不是运算符逗号(因为重载版本不具有用户期望的序列点.所以支持它的动力甚至比最初的要少.


Jar*_*Par 6

三元运算符的原理之一是仅基于条件表达式的真或假来评估真/假表达式.

cond ? expr1 : expr2
Run Code Online (Sandbox Code Playgroud)

在此示例expr1中,仅评估if是否cond为true,而expr2仅评估if是否cond为false.牢记这一点让我们看一下三元重载的签名是什么样的(为了简单起见,使用固定类型而不是模板)

Result operator?(const Result& left, const Result& right) { 
  ...
}
Run Code Online (Sandbox Code Playgroud)

这个签名根本不合法,因为它违反了我所描述的确切语义.为了调用这种方法,语言必须对两者进行评估expr1,expr2因此不再对它们进行有条件的评估.为了支持三元运营商要么需要

  1. 为每个值取一个lambda,以便按需生成它们.这必然会使调用代码复杂化,因为它必须考虑lambda调用语义,其中没有lambda在逻辑上存在
  2. 三元运算符需要返回一个值来表示编译器是否应该使用expr1expr2

编辑

有些人可能认为在这种情况下缺乏短路是好的.原因是C++已经允许你违反运算符重载的短路||&&

Result operator&&(const Result& left, const Result& right) { 
  ...
}
Run Code Online (Sandbox Code Playgroud)

虽然我仍然觉得这种行为令人困惑,即使对于C++也是如此.