Why does < instead of << in stream output still compile?
Asked Answered
T

2

11

Today I made a small typo in my program, and was wandering why I wasn't getting any output, although the program compiled fine. Basically it reduces to this:

#include <iostream>

int main()
{
    std::cout < "test"; // no << but <
}

I have absolutely no idea what kind of implicit conversion is performed here so the program still compiles (both g++4.9.2 and even g++5). I just realized that clang++ rejects the code. Is there a conversion to void* being performed (cannot think of anything else)? I remember seeing something like this, but I thought it was addressed in g++5, but this doesn't seem to be the case.

EDIT: I was not compiling with -std=c++11, so the code was valid in pre-C++11 (due to conversion to void* of ostream). When compiling with -std=c++11 g++5 rejects the code, g++4.9 still accepts it.

Thought answered 18/4, 2015 at 22:6 Comment(6)
I get a warning from g++ 4.9.2 about an unused computed value though when using -Wall though.Iberia
@Raphael indeed, when I compiled I didn't look at all warnings, now I see and realized what happened, although gotta say it is a bit unusual. I use most of the time -Wall, however this was a tiny piece of code that I compiled in sublime text and realized it magically worksThought
Why this gives 0 as an output ?Hubey
@Hubey Because you end up comparing 2 pointers: (void*)std::cout with a string literal decayed to a const char pointer, and the comparison seem to be false. See the answers to understand why the conversion.Thought
@vsoftco: pointer comparison of this type is unspecified behavior according to C++ standard. See thisHubey
@Hubey Yes I know, you asked why and I told you. The compiler can do whatever it wants.Thought
C
9

Yes, the compiler is converting cout to a void*. If you use the -S switch to get the code's disassembly, you'll see something like this:

    mov edi, OFFSET FLAT:std::cout+8
    call    std::basic_ios<char, std::char_traits<char> >::operator void*() const
    cmp rax, OFFSET FLAT:.LC0
    setb    al
    test    al, al

Which makes it clear that operator void* is the culprit.

Contrary to what Bill Lynch said, I'm able to reproduce it with —std=c++11 on Compiler Explorer. However, it does appear to be an implementation defect, since C++11 should have replaced operator void* with operator bool on basic_ios.

Chinkiang answered 18/4, 2015 at 22:11 Comment(4)
In c++11, there is no operator void *() on std::ostream. So that would be an implementation defect.Unadvised
I think it is a defect in g++4.9 (g++5 rejects it)Thought
g++ 4.9 isn't fully C++11 compliant in some points to not break it's ABI. This is one of the things. g++ 5 will be fully C++11 compliant.Iberia
Yes, I just double-checked that this was changed in C++11.Chinkiang
U
5

This is only valid before C++11.

You're basically doing: ((void *) std::cout) < ((char *) "test")

Unadvised answered 18/4, 2015 at 22:9 Comment(1)
sorry, I take it back, was not using -std=c++11.... g++5 rejects it indeed, g++4.9.2 doesn't, even with -std=c++11.Thought

© 2022 - 2024 — McMap. All rights reserved.