26

Why in conditional operator(?:), second and third operands must have the same type?

My code like this:

#include <iostream>
using std::cout;

int main()
{
    int a=2, b=3;
    cout << ( a>b ? "a is greater\n" : b );  /* expression ONE */
    a>b? "a is greater\n" : b;               /* expression TWO */

    return 0;
}

When compile it using g++, it issue an error:

main.cpp:7:36: error: operands to ?: have different types ‘const char*’ and ‘int’
main.cpp:8:28: error: operands to ?: have different types ‘const char*’ and ‘int’

I wonder why they must have the same type?

(1) In my opinion, if (a>b) is true, then the expression ( a>b ? "a is greater\n" : b )will return "a is greater\n" and cout << "a is greater\n" will output that string;
otherwise the expression will return b, and cout << b will output the value of b.

But, unfortunately it is not like this. WHY?

(2) The second expression gets the same error.

PS: I know, it is the standard who says it must be like this, but, why the standard say so?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Yishu Fang
  • 9,448
  • 21
  • 65
  • 102
  • 5
    Note that they don't necessarily have to have the exact same type; some conversions can take place, but the number of allowable conversions are very few to avoid unintended behavior. – James McNellis Mar 12 '12 at 05:04
  • 1
    [Related](http://stackoverflow.com/questions/8324338/compiler-error-for-conditional-operator-when-used-with-typecasting-operator). – iammilind Mar 12 '12 at 05:19

5 Answers5

41

You should try to decompose what's happening to understand:

cout << ( a>b ? "a is greater\n" : b );

This translates to :

operator<<(cout, ( a>b ? "a is greater\n" : b ));

At that stage the compiler must choose one of the following overloads:

ostream& operator<<(ostream&, int);
ostream& operator<<(ostream&, const char*);

But it can't because the type of result of the ternary operator is not known yet (only at runtime).

To make things clearer think like this:

 auto c = a>b ? "test" : 0;

What would be the type of c ? It can't be decided at compile time. C++ is a statically typed language. All types must be known at compile time.

EDIT:

You are thinking of a ? b : c in the following way:

if (a)
    b;
else
    c;

While it is actually this:

if (a)
    return b;
else
    return c;
J.N.
  • 8,203
  • 3
  • 29
  • 39
  • Thank you, but what about the second expression? I do not intend to assign it to anyone else. @J.N. – Yishu Fang Mar 12 '12 at 05:08
  • 3
    @UniMouS you don't assign to anyone else, but you could. The ternary operator is defined as returning a value. You are simply ignoring it, but it's there. – J.N. Mar 12 '12 at 05:09
  • 2
    @UniMouS, your second expression would work if you'd write it as `a>b? (void)"a is greater\n" : (void)b;` that is if you'd tell the compiler to throw away the values of the subexpressions. – Jens Gustedt Mar 12 '12 at 07:50
  • 'auto c = a>b ? "test" : 0;' might not be a good example. Because the constant 0 CAN be used as a NULL pointer to assign to a pointer of any type, 'a>b ? "test" : 0' is valid and its type is 'char*' (or 'const char*' in C++). – xiaokaoy Aug 26 '17 at 03:03
8

I wonder why they must have the same type?

In C++ any expression must have a single type, and the compiler should be able to deduce it at compile time.

This stems from the fact that C++ is a statically typed language wherein all types must be known at compile time.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Alok Save
  • 202,538
  • 53
  • 430
  • 533
6

They don't really have to be the same type. For example, an expression like: int a = argc > 1 ? 2 : 'a'; is entirely permissible, even though 2 is of type int, and 'a' is of type char.

There does have to be an implicit conversion to the same type though. The reason is simple: the operator has to yield one value, and the compiler has to be able to figure out the type of that value. If there's no implicit conversion between the two types, there's no one type for the expression to produce.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
3

the ?: expression will produce a value(called rvalue), which is to be assigned to a variable(which is called lvalue), as J.N. metioned, C++ is a statically typed language, lvalue must be known at compile time.

int num = a>b ? a : "eh, string?";

The code above won't compile, cause the variable num can only hold an int, string is not allowed.

neevek
  • 11,760
  • 8
  • 55
  • 73
2

It's a strong type language and it need to treat the whole ?: as a variable or statement, like:

int i = 3;
int j = 5;
int k = (2 > 1 ? i : j) + 3;

in such a case, what would you expect it should do for you if i is a string?

Simon Wang
  • 2,843
  • 1
  • 16
  • 32