Why does cout print "2 + 3 = 15" in this snippet of code?

C++

C++ Problem Overview


Why is the output of the below program what it is?

#include <iostream>
using namespace std;

int main(){

    cout << "2+3 = " <<
    cout << 2 + 3 << endl;
}

produces

2+3 = 15

instead of the expected

2+3 = 5

This question has already gone multiple close/reopen cycles.

Before voting to close, please consider this meta discussion about this issue.

C++ Solutions


Solution 1 - C++

Whether intentionally or by accident, you have << at the end of the first output line, where you probably meant ;. So you essentially have

cout << "2+3 = ";  // this, of course, prints "2+3 = "
cout << cout;      // this prints "1"
cout << 2 + 3;     // this prints "5"
cout << endl;      // this finishes the line

So the question boils down to this: why does cout << cout; print "1"?

This turns out to be, perhaps surprisingly, subtle. std::cout, via its base class std::basic_ios, provides a certain type conversion operator that is intended to be used in boolean context, as in

while (cout) { PrintSomething(cout); }

This is a pretty poor example, as it's difficult to get output to fail - but std::basic_ios is actually a base class for both input and output streams, and for input it makes much more sense:

int value;
while (cin >> value) { DoSomethingWith(value); }

(gets out of the loop at end of stream, or when stream characters do not form a valid integer).

Now, the exact definition of this conversion operator has changed between C++03 and C++11 versions of the standard. In older versions, it was operator void*() const; (typically implemented as return fail() ? NULL : this;), while in newer it's explicit operator bool() const; (typically implemented simply as return !fail();). Both declarations work fine in a boolean context, but behave differently when (mis)used outside of such context.

In particular, under C++03 rules, cout << cout would be interpreted as cout << cout.operator void*() and print some address. Under C++11 rules, cout << cout should not compile at all, as the operator is declared explicit and thus cannot participate in implicit conversions. That was in fact the primary motivation for the change - preventing nonsensical code from compiling. A compiler that conforms to either standard would not produce a program that prints "1".

Apparently, certain C++ implementations allow mixing and matching the compiler and the library in such a way that produces non-conforming outcome (quoting @StephanLechner: "I found a setting in xcode which produces 1, and another setting that yields an address: Language dialect c++98 combined with "Standard library libc++ (LLVM standard library with c++11 support)" yields 1, whereas c++98 combined with libstdc (gnu c++ standard library) yields an address;"). You can have a C++03-style compiler that doesn't understand explicit conversion operators (which are new in C++11) combined with a C++11-style library that defines the conversion as operator bool(). With such a mix, it becomes possible for cout << cout to be interpreted as cout << cout.operator bool(), which in turn is simply cout << true and prints "1".

Solution 2 - C++

As Igor says, you get this with a C++11 library, where std::basic_ios has the operator bool instead of the operator void*, but somehow isn't declared (or treated as) explicit. See here for the correct declaration.

For example, a conforming C++11 compiler will give the same result with

#include <iostream>
using namespace std;

int main() {
    cout << "2+3 = " << 
    static_cast<bool>(cout) << 2 + 3 << endl;
}

but in your case, the static_cast<bool> is being (wrongly) allowed as an implicit conversion.


Edit: Since this isn't usual or expected behaviour, it might be useful to know your platform, compiler version, etc.


Edit 2: For reference, the code would usually be written either as

    cout << "2+3 = "
         << 2 + 3 << endl;

or as

    cout << "2+3 = ";
    cout << 2 + 3 << endl;

and it's mixing the two styles together that exposed the bug.

Solution 3 - C++

The reason for the unexpected output is a typo. You probably meant

cout << "2+3 = "
     << 2 + 3 << endl;

If we ignore the strings that have the expected output, we are left with:

cout << cout;

Since C++11, this is ill-formed. std::cout is not implicitly convertible to anything that std::basic_ostream<char>::operator<< (or a non member overload) would accept. Therefore a standards conforming compiler must at least warn you for doing this. My compiler refused to compile your program.

std::cout would be convertible to bool, and the bool overload of the stream input operator would have the observed output of 1. However, that overload is explicit, so it shouldn't allow an implicit conversion. It appears that your compiler/standard library implementation doesn't strictly conform to the standard.

In a pre-C++11 standard, this is well formed. Back then std::cout had an implicit conversion operator to void* which has a stream input operator overload. The output for that would however be different. it would print the memory address of the std::cout object.

Solution 4 - C++

The posted code should not compile for any C++11 (or later conformant compiler), but it should compile without even a warning on pre C++11 implementations.

The difference is that C++11 made the convertion of a stream to a bool explicit:

> C.2.15 Clause 27: Input/output library [diff.cpp03.input.output] 27.7.2.1.3, 27.7.3.4, 27.5.5.4

> Change: Specify use of explicit in existing boolean conversion operators
Rationale: Clarify intentions, avoid workarounds.
Effect on original feature: Valid C++ 2003 code that relies on implicit boolean conversions will fail to compile with this International Standard. Such conversions occur in the following conditions:

> * passing a value to a function that takes an argument of type bool;
...

ostream operator << is defined with a bool parameter. As a conversion to bool existed (and was not explicit) is pre-C++11, cout << cout was translated to cout << true which yields 1.

And according to C.2.15, this should not longer compile starting with C++11.

Solution 5 - C++

You can easily debug your code this way. When you use cout your output is buffered so you can analyse it like this:

Imagine first occurence of cout represents the buffer and operator << represents appending to the end of the buffer. Result of operator << is output stream, in your case cout. You start from:

cout << "2+3 = " << cout << 2 + 3 << endl;

After applying the above stated rules you get a set of actions like this:

buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

As I said before the result of buffer.append() is buffer. At the begining your buffer is empty and you have the following statement to process:

statement: buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

buffer: empty

First you have buffer.append("2+3 = ") which puts the given string directly into the buffer and becomes buffer. Now your state looks like this:

statement: buffer.append(cout).append(2 + 3).append(endl);

buffer: 2+3 = 

After that you continue to analyze your statement and you come across cout as argument to append to the end of buffer. The cout is treated as 1 so you will append 1 to the end of your buffer. Now you are in this state:

statement: buffer.append(2 + 3).append(endl);

buffer: 2+3 = 1

Next thing you have in buffer is 2 + 3 and since addition has higher precedence than output operator you will first add these two numbers and then you will put the result in buffer. After that you get:

statement: buffer.append(endl);

buffer: 2+3 = 15

Finally you add value of endl to the end of the buffer and you have:

statement:

buffer: 2+3 = 15\n

After this process the characters from the buffer are printed from the buffer to standard output one by one. So the result of your code is 2+3 = 15. If you look at this you get additional 1 from cout you tried to print. By removing << cout from your statement you will get the desired output.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHokhy TannView Question on Stackoverflow
Solution 1 - C++Igor TandetnikView Answer on Stackoverflow
Solution 2 - C++UselessView Answer on Stackoverflow
Solution 3 - C++eerorikaView Answer on Stackoverflow
Solution 4 - C++Serge BallestaView Answer on Stackoverflow
Solution 5 - C++Ivan KulezicView Answer on Stackoverflow