6

Inspired by my observation in a previous question, I decided to do a little test:

#include <iostream>
#include <sstream>

int main()
{
  char c = 'A';
  std::stringstream ss("B");

  // I know this is bad mojo; that's why I'm testing it
  ss >> char(c);

  std::cout << c << std::endl;
}

My compiler version:

Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix

Compiling clang in C++03 mode, it compiles and runs okay:

$ clang++ -Wall -pedantic -std=c++03 test.cpp 
test.cpp:9:6: warning: expression result unused [-Wunused-value]
  ss >> char(c);
  ~~ ^  ~~~~~~~
1 warning generated.
$ ./a.out 
A

It prints out A, which is fine, given that this code shouldn't even compile. Switching to C++11 mode, it properly errors when compiling (error: invalid operands to binary expression ('std::stringstream' (aka 'basic_stringstream<char>') and 'int')).

Yes, in C++03 mode it does give a warning, but it's not a warning I'd expect (I expected some kind of "taking temporary by reference" warning/error, or perhaps a warning/error saying no operator>> accepts a char parameter).

My question is: why does the code successfully compile in C++03 mode? Is it using some alternative overload of operator>> that avoids taking the temporary by reference? Is it being overly lax and letting me take the temporary by reference? I'm puzzled at why clang accepts this code at all; GCC 4.9 properly errors out in C++03/11 modes with a much more relevant error (error: no match for 'operator>>' (operand types are 'std::stringstream {aka std::basic_stringstream<char>}' and 'char')). Clang's behavior in C++03 mode is puzzling me.

Community
  • 1
  • 1
Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • 2
    My version (`clang version 3.5.0 (tags/RELEASE_350/final), Target: x86_64-unknown-linux-gnu, Thread model: posix`) errors out properly, so it's possible that it is a bug that has been fixed. – Daniel Kamil Kozar Sep 13 '14 at 15:02
  • I'd expect 5.1 to be later than 3.5.0. So if anything, it has been introduced, not fixed. – celtschk Sep 13 '14 at 17:15
  • 1
    @celtschk 5.1 is Apple's version number. It's based off of 3.4svn, so 3.5 is newer. – sepp2k Sep 13 '14 at 17:28
  • @DanielKamilKozar: Alternatively, it could be from a difference in libc++ vs libstdc++. – Bill Lynch Sep 13 '14 at 17:40

1 Answers1

2

I think it invokes the operator bool() of std::stringstream, that is, the code is interpreted as

bool(ss) >> char(c);

which of course is a valid statement with no effect. The implicit conversion to bool returns !fail() and is what allows code like

while (ss >> foo)
  ...

The standard allows to convert to another type that converts to bool instead of plain bool (for example a void*) exactly to avoid this type of problem. Apparently your implementation does not make use of that freedom.

celtschk
  • 19,311
  • 3
  • 39
  • 64