简体   繁体   中英

Mistake with streaming and conditional operators

I recently came across a bug in my code, which I think might be a common mistake. I've generalized the mistake, and I'd like to understand why this does not generate a compiler warning or error. Thanks in advance.

The mistake is the following use of a conditional operator and streaming operator to cout:

int i=0;
int array[] = {1};
std::cout << false ? array[i++] : 2;
std::cout << std::endl << "i = " << i << std::endl;

// output:
// 0
// i = 1

I'm assuming the first number printed 0 is the numeric representation of false . I'm not sure how the compiler interprets the rest. The array[i++] is getting evaluated because i has been incremented. This must be valid syntax, but the interpretation is not at all expected. Or is it?


For those who made the same mistake but do not know the fix, the corrected code has parentheses around the conditional operator:

int i=0;
int array[] = {1};
std::cout << (false ? array[i++] : 2);
std::cout << std::endl << "i = " << i << std::endl;

// output:
// 2
// i = 0

Also, calling the streaming operator after the conditional operation would have generated a compiler error:

int i=0;
int array[] = {1};
std::cout << false ? array[i++] : 2 << std::endl;
std::cout << std::endl << "i = " << i << std::endl;

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

I'm assuming the first number printed 0 is the numeric representation of false.

Correct.

I'm not sure how the compiler interprets the rest.

? : ? : is the ternary conditional operator. The first subexpression ( std::cout << false ) is evaluated as a boolean, and if it is true, then the middle subexpression is evaluated ( array[i++] ), otherwise the last subexpression is evaluated ( 2 ).

std::cout is of type std::ostream . The stream insertion operator returns the stream itself. The stream has a conversion operator to boolean (since C++11; prior the conversion operator is to a void pointer, which has the same behaviour in this case). The behaviour of the conversion operator is:

Returns true if the stream has no errors and is ready for I/O operations.

Since there was no errors with the output stream, the conversion returns true, and therefore the middle subexpression ( array[i++] ) is evaluated.

I'd like to understand why this does not generate a compiler warning or error.

Because there is no error and (arguably) nothing to warn about. You may have intended to write something else, but what you did write is a valid program and the compiler cannot read your mind to find out that this is not what you had intended.

Note that if you removed any side effects from the ternary results: std::cout << false ? array[i] : 2; std::cout << false ? array[i] : 2; , then a compiler would likely warn you because the top level expression now has no side-effects.

PS Clang does warn about your program if you've enabled warnings:

main.cpp:7:20: warning: operator '?:' has lower precedence than '<<'; '<<' will be evaluated first [-Wparentheses]
std::cout << false ? array[i++] : 2;
~~~~~~~~~~~~~~~~~~ ^
main.cpp:7:20: note: place parentheses around the '<<' expression to silence this warning
std::cout << false ? array[i++] : 2;
                   ^
main.cpp:7:20: note: place parentheses around the '?:' expression to evaluate it first
std::cout << false ? array[i++] : 2;
 int i = 0; std::cout << false ? array[i++] : 2; 

The result of std::cout.operator<<(bool) converts to boolean true if std::cout is not in error, fail ... state. i++ gets evaluated and the whole statement yields array[0] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM