8

この単純なプログラム (Linux でコンパイルされた場合) は、コンパイルされているかどうかに基づいて、2 つの異なる答えを正しく返します-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

1 つ目は 16 進アドレスを出力し、2 つ目は "Hello" を出力します。これは正しい動作です。これは、演算子<<が 2 つの異なるものに解決されるためです (C++03 には右辺値参照がないため、これで終わりです)。

次に、OS X で同じことを試してください。


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

(これにより、16 進出力が正しく生成されます。)


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

(おっと...まだ 16 進数の出力です...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 で異なる結果が生成される理由は、以下の回答の 1 つで強調表示されています。

4

2 に答える 2

18

まず、動作の予想される違いは、operator<<(std::ostream&, const char*)オーバーロード (実際には関数テンプレートの特殊化ですが、今のところ気にしないでください) には型のパラメーターがstd::ostream&あり、左辺値参照は左辺値にのみバインドでき、あなたの例ではストリームは右辺値であるためです。そのオーバーロードは使用できません。C++03 では、メンバー関数は右辺値オブジェクトで呼び出すことができるstd::ostream::operator<<(const void*)ため、有効なオーバーロードはメンバー関数だけであることを意味し、文字列は16 進数のアドレスとして書き出されます。C++11 には、右辺値ストリームへの書き込みを許可する新しい関数テンプレートがあり、オーバーロードに転送されるため、16 進アドレスではなく文字列が出力されます。void*operator<<(std::ostream&&, const T&)operator<<(std::ostream&, const char*)

GNU/Linux では、コンパイラ (g++) と標準ライブラリ (libstdc++) の両方で C++11 がかなり適切にサポートされている、かなり最近の GCC リリースを使用していると思われますoperator<<(std::ostream&&, const T&)

OS X では、GCC の標準ライブラリ libstdc++ で Clang を使用している可能性があります。Xcode にはデフォルトで古いバージョンの GCC (4.2) が付属しており、GCC 4.2 の標準ライブラリは C++11 をサポートしていないためoperator<<、右辺値ストリームのオーバーロードがありません。Using-std=c++0xは Clang に C++11 言語機能 (右辺値参照など) をサポートするように指示しますが、GCC 4.2 のライブラリが魔法のように C++11 コードを成長させることはありません。解放された。Apple は、非有史以前の libstdc++ を出荷する代わりに、LLVM および Clang プロジェクトに対応する独自の標準ライブラリ実装を作成しました。Using-stdlib=libc++は、古い libstdc++ の代わりにその libc++ 標準ライブラリ実装を使用するように clang に指示します。libc++ は最近書かれたので、operator<<右辺値参照のオーバーロード。

于 2013-01-04T02:51:22.610 に答える
7

libc++ ではなく、デフォルトで libstdc++ を使用する clang に問題があるようです。次のようにコンパイルclang++ -std=c++0x -stdlib=libc++ test.cppすると、期待される出力が得られます。

于 2013-01-04T02:02:46.920 に答える