1

現在、テンプレートに関する本を読んでおり、次の例が示されています。

#include <string>

// note: reference parameters
template <typename T>
inline T const& max (T const& a, T const& b)
{
    return  (a < b)  ?  (b) : (a);
}

int main()
{
    char* a="apple";
    char* p="peach"; 
    ::max(a,p);   // OK, BUT 
    ::max("apple","peach");//  <<<< ERROR IN VISUAL STUDIO 2012, WHY?
}

VS2012 が次のように言う理由がわかりません。

エラー C2440: 'return': 'const char *' から 'const char (&)[6]' に変換できません

誰かが私にこれを説明してもらえますか? 本にはこれでいいと書いてありますが、古い本なので、まだ新しい本を待っています。

4

3 に答える 3

3

問題は、2 番目のケースでは、6 文字の配列への参照であるT const&に推測されることです。const char(&)[6]

VS2012 では、 を使用して比較を行うと、?:への配列参照が減衰し、char*参照として返すことができなくなります。GCC 4.7.2 では、この減衰は見られません ( https://ideone.com/yIBZWiを参照)。

以下のコンパクトでないバージョンを試していただけますか (手元に VS2012 がありません)。リターンで a と b を一緒に使用しないことで、減衰を回避できるはずです。

template <typename T>
inline T const& max (T const& a, T const& b)
{
    if(a<b)
       return b;
    else
       return a;
}
于 2013-06-26T14:26:35.833 に答える
1

エラーの理由は次のとおりです。

文字列リテラルの型const char[X]は で、X はゼロ区切り文字を含む文字列の長さです。あなたの場合は 6 なので、合計Tconst char[6]です。
C 配列を関係演算子と比較することはできないため、コンパイラは「配列からポインターへの減衰」を適用します。つまり(a < b)、a と b はポインターとして扱われます。
Visual Studio がその減衰を式全体に適用しているように見えます。つまり、a と b もポインタとして扱い(b) : (a)ます。
式全体の型は になりますchar const*が、戻り値の型はでありT const&、つまりconst char(&)[6]であり、ポインターを逆方向に変換することはできません。VS2012のバグだと思います。

更新: これがバグであるという主張を裏付ける標準的な引用は次のとおりです:
§5.16,4:

2 番目と 3 番目のオペランドが同じ値カテゴリの glvalue で、同じ型の場合、結果はその型と値カテゴリになります [...]

Sidenote 1 : を含めること<string>はできません。std::string文字列リテラルは、C との下位互換性を保つために、ほとんどの s ではないことに注意してください。補足
2 : 文字列リテラルを に割り当てますchar *。文字列リテラルは typeであるため、下位互換性の理由から、char const[]それらを に減衰させることは特殊です。char*実際にそのポインターの背後にある文字列を非定数として扱い、それらに書き込むと、未定義の動作が発生します。したがって、優先char const*して、コンパイラはとにかくそれらについて警告する必要があります。
補足3: C++ では、ポインターは完全に順序付けされていません。したがって、崩壊した配列の比較、つまり max 関数内のポインターの意味は、移植可能なプログラムでは避けたい実装定義です。文字列リテラルの内容ではなく、アドレスを比較するため、とにかく意味がありません。 補足 4 : "apple" と "peach" が同じ長さであることは幸運でした。そうでない場合、たとえば「リンゴ」や「桃」の場合、コンパイラは型の char リテラルを見const char[7]const char[8]、何Tをすべきかを認識しません: http://ideone.com/fp2WmJ

于 2013-06-26T14:35:49.483 に答える
0

関数 template のインスタンス化中maxに、テンプレート パラメーターTが引数から推定されます。あなたの例では、char const [6]6文字の配列であるタイプです。

この式(a < b) ? (b) : (a)は、 と の両方(a)(b)ポインターに変換します (ルール 5.16.6、「配列からポインターへ (4.2)、[...] 標準変換は 2 番目と 3 番目のオペランドで実行されます」。)

次に、コンパイラは結果char const *を a T(戻り値の型) に変換しようとします。これは achar const[6]であるため、エラーになります。

GCC は、配列が同じ型(つまり、同じサイズの char の配列) である場合、配列をポインターに変換しないため、この動作を示しません。2 つの char 配列のサイズが異なる限り、エラーは引き続き表示されます。

とにかく、char 配列の比較はおそらくあなたが思うようには機能しないので、std::string代わりに使用する方がよいでしょう。

于 2013-06-26T14:45:55.433 に答える