在OS X上,简单的C++程序给出了不正确的结果(这是命令行选项'c ++ 03'vs'c ++ 11'的结果)

Bad*_*ild 8 c++ linux macos rvalue operator-keyword

这个简单的程序(在Linux上编译时)将根据是否编译而正确地给出两个不同的答案-std=c++0x.

问题:我无法在OS X(Mountain Lion,10.8 SDK)上重现同样的事情.我错过了什么?

#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;
}
Run Code Online (Sandbox Code Playgroud)

要了解我的意思,请执行以下操作(首先在Linux上,看看它应该如何工作):

> g++ main.cpp
> ./a.out
0x401471
Run Code Online (Sandbox Code Playgroud)
> g++ -std=c++0x main.cpp
> ./a.out
Hello
Run Code Online (Sandbox Code Playgroud)

第一个将打印十六进制地址,第二个将打印"Hello".这是正确的行为,因为操作符<<解析为两个不同的东西(C++ 03中没有右值引用,所以你去了).

现在,在OS X上尝试相同的事情:


> xcrun c++ main.cpp
> ./a.out
0x10840dd88
Run Code Online (Sandbox Code Playgroud)

(这正确地产生十六进制输出.)


> xcrun c++ -std=c++0x main.cpp
> ./a.out
0x10840dd88
Run Code Online (Sandbox Code Playgroud)

(糟糕...仍然是十六进制输出......我们处于C++ 11x模式,但是可能没有使用正确的标头?)


注意:编译器的版本在这里:

> 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
Run Code Online (Sandbox Code Playgroud)

注意:这本身不是C++问题,而是OS X构建问题.对于那些有兴趣谁,它产生与C++ 03和C++ 11种不同结果的原因是其中一个答案下方突出.

Jon*_*ely 18

首先,行为的预期差异是因为operator<<(std::ostream&, const char*)重载(它实际上是一个函数模板特化,但现在永远不知道)有一个类型的参数,std::ostream&而左值引用只能绑定到左值,在你的例子中,流是一个右值,所以不能使用过载.在C++ 03中,这意味着唯一可行的重载是std::ostream::operator<<(const void*)成员函数,因为可以在rvalue对象上调用成员函数,因此字符串void*以十六进制形式写出.在C++ 11中有一个新的operator<<(std::ostream&&, const T&)函数模板,它允许写入rvalue流,并转发到operator<<(std::ostream&, const char*)重载,因此输出字符串而不是十六进制地址.

在GNU/Linux上,你可能会使用一个相当新的GCC版本,它在编译器(g ++)和标准库(libstdc ++)中对C++ 11有相当好的支持,所以它有operator<<(std::ostream&&, const T&)重载和一切Just Works.

在OS X上,您可能正在使用Clang和GCC的标准库libstdc ++.默认情况下,Xcode附带一个古老版本的GCC(4.2),而GCC 4.2中的标准库不支持C++ 11,因此没有operator<<rvalue流的重载.使用-std=c++0x告诉Clang支持C++ 11语言特性(例如rvalue引用),但是并没有神奇地让GCC 4.2的库增长C++ 11代码,当GCC 4.2时,标准委员会眼中的代码甚至没有闪烁被释放了.而不是运送非史前的libstdc ++ Apple,而是编写自己的标准库实现,以配合LLVM和Clang项目.使用-stdlib=libc++tell clang来使用libc ++标准库实现而不是古老的libstdc ++.由于最近编写了libc ++,因此它具有operator<<rvalue引用的重载.


Jon*_*ier 7

对于使用libstdc ++而非libc ++的clang来说,这似乎是一个问题.像这样编译:clang++ -std=c++0x -stdlib=libc++ test.cpp产生预期的输出.