如何确定三元运算符的返回类型?

时间:2019-08-07 19:07:35

标签: c++ ternary-operator operator-precedence

我正在解决有关主教在棋盘上移动的问题。在代码的某一点上,我有以下语句:

std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;

这会产生以下错误:

error: invalid operands of types 'int' and '<unresolved overloaded function type>' to binary 'operator<<'

但是,我通过在代码中包含一个附加变量来立即修复此错误:

int steps = (abs(c2-c1) == abs(r2-r1)) ? 1 : 2;
std::cout << steps << std::endl;

三元运算符如何工作,如何确定其返回类型(如编译器称为<unresolved overloaded function type>)?

6 个答案:

答案 0 :(得分:65)

这与推论返回类型以及与operator precedence有关的一切都没有关系。当你有

-1 if x < -.1 else 0

不是

std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;

因为std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl; 的优先级低于?:。这意味着您实际拥有的是

<<

这就是为什么您收到关于(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl); 的错误的原因。只需使用

这样的括号即可
<unresolved overloaded function type>

你会没事的。

答案 1 :(得分:11)

您必须在三元运算符后加上括号:

std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;

如果不是<<运算符,则转到2并给出错误,因为它没有这样的重载函数。

之所以发生这种情况,是因为按位左移运算符(<<)的优先级高于三元运算符。您可以在this page of the C++ reference中查看运算符的完整列表及其优先级。

答案 2 :(得分:8)

由于operator precedence,该行被视为:

(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl);

将其更改为

std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
//           ^----------------------------------^
//           Surrounding parentheses

答案 3 :(得分:5)

当可视化解析顺序时,很容易看到错误:

std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
\_______/                                                      <--- #1
             \________________________/   V   \~~~~error~~~/   <--- #2
             \_____________________________________________/   <--- #3
\__________________________________________________________/   <--- #4
\___________________________________________________________/  <--- #5

答案 4 :(得分:3)

您提出的问题的字面上答案是[expr.cond] secton of the C++ language standard.

中的算法

基本规则“确定是否可以从第二个操作数到为第三个操作数确定的目标类型形成隐式转换序列,反之亦然。”如果没有可能的转换,或者有多个以上的转换,这是一种语法错误,但是有几种特殊情况(此处不适用):

  • 如果两者都是算术类型或enum类型,则将为p ? a : b获得相同类型的隐式转换,该隐式转换确定表达式的类型,例如a + ba * b
  • 目标之一可能是throw表达式,并被视为具有另一个类型。
  • 如果目标之一是位字段,则条件表达式的类型也是如此
  • 具有不同限定词(例如constvolatile)的指针的限定词是统一的。

如果目标是相同类型的glvalue,则结果为glvalue,否则为prvalue。

如有疑问,您始终可以显式地强制转换其中一个或两个操作数,以便它们具有相同的类型。

您的实际问题是运算符的优先级,如公认的答案所解释。也就是说,编译器将第三个操作数解析为2 << std::endl,而不是2。

答案 5 :(得分:0)

根据cppreference

  

在解析表达式时,在表的上一行中具有优先级的运算符将比在其下一行中带有运算符的任何运算符更严格地(如用括号括起来)绑定到其参数。较低的优先级。例如,表达式std::cout << a & b*p++被解析为(std::cout << a) & b*(p++),而不是std::cout << (a & b)(*p)++

     

具有相同优先级的运算符在其关联性的方向上绑定到其参数。例如,由于赋值从右到左的关联,表达式a = b = c被解析为a = (b = c),而不是(a = b) = c,而a + b - c被解析为{{1} },而不是(a + b) - c,因为加法和减法从左到右具有关联性。

     

关联性规范对于一元运算符来说是多余的,仅出于完整性考虑而显示:一元前缀运算符始终从右向左关联(a + (b - c)delete ++*p,一元后缀运算符总是从左至右关联(delete (++(*p)))a[1][2]++。请注意,即使成员访问运算符与一元后缀运算符组合在一起,关联性也很有意义:((a[1])[2])++被解析为a.b++而不是{ {1}}。

     

运算符优先级不受运算符重载的影响。例如,(a.b)++解析为a.(b++),因为算术左移的优先级高于条件运算符。