这个简单的程序(在Linux上编译时)将根据其是否编译正确地给出两个不同的答案-std=c++0x。
-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; }
要了解我的意思,请执行以下操作(首先在Linux上,仅查看其工作方式):
> g++ main.cpp > ./a.out 0x401471
> g++ -std=c++0x main.cpp > ./a.out Hello
第一个将打印一个十六进制地址,第二个将打印“ Hello”。这是正确的行为,这是因为运算符<<解析为两种不同的情况(C ++ 03中没有右值引用,因此可以使用)。
<<
现在,在OS X上尝试相同的操作:
> xcrun c++ main.cpp > ./a.out 0x10840dd88
(这将正确产生十六进制输出。)
> xcrun c++ -std=c++0x main.cpp > ./a.out 0x10840dd88
(糟糕……仍然是十六进制输出……我们处于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
注意:这本身不是C 问题,而是OS X构建问题。对于那些感兴趣的人,下面在答案之一中突出说明了它与C 03和C ++ 11产生不同结果的原因。
首先,行为上的预期差异是因为operator<<(std::ostream&, const char*)重载(实际上是函数模板的专门化,但暂时不要紧)具有类型参数,std::ostream&并且左值引用只能绑定到左值,并且在您的示例中,流是右值,因此无法使用重载。在C 03中,这意味着唯一可行的重载是std::ostream::operator<<(const void*)成员函数,因为 可以 在rvalue对象上调用成员函数,因此该字符串void*以十六进制形式写为地址。在C 11中,有一个新的operator<<(std::ostream&&, const T&)函数模板,该模板允许写入右值流并转发给operator<<(std::ostream&, const char*)重载,因此输出字符串而不是十六进制地址。
operator<<(std::ostream&, const char*)
std::ostream&
std::ostream::operator<<(const void*)
void*
operator<<(std::ostream&&, const T&)
在GNU / Linux上,您大概使用的是最新版本的GCC版本,该版本在编译器(g )和标准库(libstdc )中都对C ++ 11有很好的支持,因此它具有operator<<(std::ostream&&, const T&)重载功能,并且一切正常。
在OS X上,您可能将Clang与GCC的标准库libstdc 一起使用。Xcode默认附带一个古老版本的GCC(4.2),而GCC 4.2中的标准库不支持C 11,因此不存在operator<<右值流的重载。using -std=c++0x告诉Clang支持C 11语言功能(例如右值引用),但是并不能神奇地使GCC 4.2的库增长C 11代码,而当GCC 4.2出现时,这在标准委员会看来并不是一闪而过的。被释放。苹果公司没有提供非史前的libstdc ,而是编写了自己的标准库实现与LLVM和Clang项目一起使用。using -stdlib=libc++告诉clang使用该libc 标准库实现而不是古老的libstdc 。由于libc 是最近写的,它具有operator<<右值引用的重载。
operator<<
-stdlib=libc++