8

これに関して SO に関する他の質問を見たことがありますが、完全に説明しているものはありません。以下の 2 つの状況をコンパイラが処理する正しい方法は何ですか? gcc 4.7.1 (with -std=c++0x)、VS2010、および VS2012 で試してみましたが、すべてで異なる結果が得られました。

例 1:

struct BB
{
 // generic cast
 template<typename T>
 operator T() const
 {   
   return 0;
 }

 // string cast
 operator std::string() const
 { 
   return string("hello");
 }
};

int main()
{
  BB b;
  string s = b;
}

出力:

  • gcc 4.7.1: わかりました
  • VS2010: わかりました
  • VS2012: 失敗: 「BB から文字列に変換できません」

例 2:

struct BB
{
 // generic cast
 template<typename T>
 operator T() const
 {   
   return 0;
 }

 // string cast
 operator std::string() const
 { 
   return string("hello");
 }
};

int main()
{
  BB b;
  string s = (string)b;

出力:

  • gcc 4.7.1: 失敗: オーバーロードされた文字列 (BB&) の呼び出しがあいまいです
  • VS2010: わかりました
  • VS2012: 失敗: 「BB から文字列に変換できません」
4

2 に答える 2

4

C スタイルのキャストを使用した 2 番目のバージョンはあいまいです。static_cast<std::string>問題は、クラスのインスタンスを文字列に変換する方法が 2 つあることBBです。明らかなパスは、テンプレート以外の std::string キャスト演算子を使用して直接文字列に変換することです。もっとよこしまな道があり、VS2010 を除くすべての人がそれを見つけました。この他のパスは、テンプレート キャスト演算子を使用して a を文字列のアロケーターに変換し、BBこのアロケーターを使用して空の文字列を構築することです。

テンプレート キャスト オペレーターは潜在的に危険な動物です。BBこれで、 aを何かに変換するツールがコンパイラに与えられました。

最初のバージョンstd::basic_string(const _Alloc& __a)は、明示的なコンストラクターであるため、この問題を回避します。明示的なコンストラクターは、明示的な変換では使用できますが、暗黙的な変換では使用できません。あいまいさを作成するのは、このコンストラクターとアロケーターへの変換であり、このパスは暗黙的な変換では使用できません。

VS1012 が暗黙の変換で失敗する理由については、VS2012 のバグである可能性があります。または、C++11 が a から a に取得するためのさらに多くの手段を作成する可能性がありBBますstd::string。私は C++11 の専門家ではありません。私は初心者でもありません。

もう 1 つ: あなたのコードは、

 std::string s;
 s = b;

テンプレート変換演算子と組み合わせた代入演算子は、 から へ取得する方法をさらに作成しbますs。システムは 、、またはに変換する必要がbありますか?std::stringcharchar*

結論: テンプレート変換演算子の使用を再考する必要があります。

于 2012-10-15T09:53:16.933 に答える
2

一部のコンパイラで失敗する理由は、何をしているのかを理解しようとしてさまざまな長さになるためです。原因は、テンプレート化されたオペレーター呼び出しです。

このSO questionが説明しているように、テンプレート化されたオペレーターは明示的に呼び出す必要があります (b.operator()<std::string>呼び出したい場合template<typename T> operator();) が、テンプレート化されたオペレーターを呼び出す方法はありません。

b.operator std::string()<std::string>; //invalid
b.operator std::string <std::string>(); //also invalid, string takes no template arguments
// a bunch more weird syntax constructions...

この問題は、後の名前operatorがテンプレート引数に依存するため、指定する方法がないことに起因します。gcc と VS2012 は、あなたが何をしていたかを理解し、テンプレートまたは明示的に定義されたものへの変換に適合できることに気付きました => あいまいな呼び出し。VS2010 はそうせず、そのうちの 1 つを呼び出しています。デバッグによってどれを見つけることができます。

テンプレートの特殊化は、このような場合に役立つ可能性がありますが、定義しようとしています

// string cast
template<>
operator std::string() const
{ 
    return string("hello");
}

コンパイラは、その関数とtemplate<>. プロトタイプにいくつかの引数があればうまくいきましたが、operator typename何かあります...

簡単に言えば、テンプレート化された変換演算子は避けてください。

于 2012-10-15T10:00:39.890 に答える