8

This simple program (when compiled on Linux) will CORRECTLY give two different answers based on whether it's compiled with -std=c++0x or not.

Problem: I cannot reproduce the same thing on OS X (Mountain Lion, 10.8 SDK). What am I missing?

#include <iostream>
#include <sstream>

class Thing : public std::ostringstream
{
public:
    Thing() : std::ostringstream() {}
    virtual ~Thing() { std::cerr << str(); }
};

int main(int argc, const char * argv[]) {
    Thing() << "Hello" << std::endl;
    return 0;
}

To see what I mean, do the following (on Linux first, just to see how it should work):

> g++ main.cpp
> ./a.out
0x401471

> g++ -std=c++0x main.cpp
> ./a.out
Hello

The first will print a hex address, the second will print "Hello". This is correct behavior and is because the operator << resolves to two different things (there are no rvalue references in C++03 so there you go).

Now, try the same thing on OS X:


> xcrun c++ main.cpp
> ./a.out
0x10840dd88

(This correctly produces the hex output.)


> xcrun c++ -std=c++0x main.cpp
> ./a.out
0x10840dd88

(Oops... still the hex output... We are in C++11x mode, but perhaps the correct headers are not being used?)


NOTE: Version of the compiler is here:

> xcrun c++ --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix

NOTE: This is not a C++ issue per se, but rather an OS X build issue. For those who are interested, the reason that it produces different results with C++03 and C++11 is highlighted below in one of the answers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Badmanchild
  • 990
  • 9
  • 18
  • 2
    I appreciate your bravery, but it's hard enough getting normal code to compile properly on OS X, let alone code adhering to the borderline of a new(ish) standard. – Charles Jan 04 '13 at 01:31
  • 2
    Note that Mountain Lion will be using Clang, not GCC. – porges Jan 04 '13 at 01:33
  • `#include < stream>` doesn't compile for me. Can you fix the include directives? -- Never mind, I took care of it. – Keith Thompson Jan 04 '13 at 01:33
  • 1
    What version of Clang are you using? – N_A Jan 04 '13 at 01:40
  • 1
    It would be nice if you included the output in your snippets, not just the commands to type, to demonstrate the different results. – Barmar Jan 04 '13 at 01:45

2 Answers2

18

Firstly, the expected difference in behaviour is because the operator<<(std::ostream&, const char*) overload (it's actually a function template specialization, but nevermind for now) has a parameter of type std::ostream& and an lvalue reference can only bind to an lvalue, and in your example the stream is an rvalue so that overload can't be used. In C++03 that means the only viable overload is the std::ostream::operator<<(const void*) member function, because member functions can be called on rvalue objects, so the string is written out as a void* address in hexadecimal. In C++11 there is a new operator<<(std::ostream&&, const T&) function template that allows writing to rvalue streams, and forwards to the operator<<(std::ostream&, const char*) overload, so the string is output rather than a hex address.

On GNU/Linux you are presumably using a fairly recent GCC release, which has fairly good support for C++11 in both the compiler (g++) and the standard library (libstdc++) so it has the operator<<(std::ostream&&, const T&) overload and everything Just Works.

On OS X you are probably using Clang with GCC's standard library, libstdc++. Xcode ships with an ancient version of GCC by default (4.2) and the standard library from GCC 4.2 doesn't support C++11, so doesn't have the operator<< overload for rvalue streams. Using -std=c++0x tells Clang to support C++11 language features (such as rvalue references), but doesn't magically make GCC 4.2's library grow C++11 code that wasn't even a twinkle in the standard committee's eye when GCC 4.2 was released. Rather than shipping a non-prehistoric libstdc++ Apple instead wrote their own standard library implementation to go with LLVM and Clang projects. Using -stdlib=libc++ tells clang to use that libc++ standard library implementation instead of the ancient libstdc++. As libc++ was written recently it has the operator<< overload for rvalue references.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
7

It appears to be an issue with clang using libstdc++ by default rather than libc++. Compiling like this: clang++ -std=c++0x -stdlib=libc++ test.cpp results in the expected output.

Jon Shier
  • 12,200
  • 3
  • 35
  • 37