5

コードは次のとおりです。

#include <iostream>
using namespace std;

// compares two objects
template <typename T> void compare(const T&, const T&){
    cout<<"T"<<endl;
};
// compares elements in two sequences
template <class U, class V> void compare(U, U, V){
    cout<<"UV"<<endl;
};
// plain functions to handle C-style character strings
void compare(const char*, const char*){
    cout<<"ordinary"<<endl;
};

int main() {

    cout<<"-------------------------char* --------------------------"<< endl;

    char* c="a";
    char* d="b";
    compare(c,d);

cout<<"------------------------- char [2]---------------------------"<< endl;

    char e[]= "a";
    char f[]="b";
    compare(e,f);

    system("pause");
}

結果は次のとおりです。

--------------------------char* ----------------------- ---

T

-------------------------- 文字[2]--------------------- --

普通

私の質問は次のとおりです: 2 つの関数の引数が char*s であるにもかかわらず、compare(c,d) が compare(const T&, const T&) を呼び出し、compare(e,f) が通常の関数を呼び出すのはなぜですか?

4

1 に答える 1

4

VS2005 は変数ef変数をconst char *型として誤って扱っているようです。

次のコードを検討してください。

#include <iostream>
using namespace std;

template <typename T> void compare (const T&, const T&) {
    cout << "T:        ";
};

template <class U, class V> void compare (U, U, V) {
    cout << "UV:       ";
};

void compare (const char*, const char*) {
    cout << "ordinary: ";
};

int main (void) {
    char* c = "a";
    char* d = "b";
    compare (c,d);
    cout << "<- char *\n";

    char e[] = "a";
    char f[] = "b";
    compare (e,f);
    cout << "<- char []\n";

    const char g[] = "a";
    const char h[] = "b";
    compare (g,h);
    cout << "<- const char []\n";

    return 0;
}

出力:

T:        <- char *
T:        <- char []
ordinary: <- const char []

C++03 のセクション13.3 Overload resolution(C++11 ではセクション番号が変更されていないように見えるため、同じコメントが適用されます) では、使用する関数を選択する方法が指定されています。標準はむしろドライリードです。

基本的に、候補関数のリストは、関数が実際にどのように呼び出されているかに基づいて作成されます (クラス/オブジェクトのメンバー関数として、通常の (装飾されていない) 関数呼び出し、ポインターを介した呼び出しなど)。

次に、それらの中から、実行可能な関数のリストが引数の数に基づいて抽出されます。

13.3.3 Best viable function次に、実行可能な関数から、最小限の暗黙的な変換シーケンス ( C++03を参照) の考え方に基づいて、最適な関数が選択されます。

本質的に、各引数に必要な暗黙の変換に基づいて設定された実行可能なリストから関数を選択するための「コスト」があります。関数を選択するコストは、その関数の個々の引数ごとのコストの合計であり、コンパイラはコストが最小の関数を選択します。

2 つの関数が同じコストで見つかった場合、標準では、コンパイラはそれをエラーとして処理する必要があると規定されています。

したがって、暗黙的な変換が 1 つの引数に対して行われる関数がある場合は、2 つの引数を同じ方法で変換する必要がある関数よりも優先されます。

「コスト」は、下の表のランク列で確認できます。完全一致はプロモーションよりもコストが低く、プロモーションはコンバージョンよりもコストが低くなります。

Rank                 Conversion
----                 ----------
Exact match          No conversions required
                     Lvalue-to-rvalue conversion
                     Array-to-pointer conversion
                     Function-to-pointer conversion
                     Qualification conversion
Promotion            Integral promotions
                     Floating point promotions
Conversion           Integral conversion
                     Floating point conversions
                     Floating-integral conversions
                     Pointer conversions
                     Pointer-to-member conversions
                     Boolean conversions

F1関数の変換コストが同じである場所F2(あなたの場合など) では、次の場合にF1優れていると見なされます。

F1 は非テンプレート関数で、F2 は関数テンプレートの特殊化です。


ただし、テンプレート コードと非テンプレート コードはすべて完全に一致するため、それだけではありません。したがって、3 番目のコードだけでなく、すべてのケースで非テンプレート関数が呼び出されることが予想されます。

それは標準でさらにカバーされています。答えはセクションにあります13.3.3.2 Ranking implicit conversion sequences。そのセクションでは、特定の条件下を除いて、同一のランクであってもあいまいさが生じると述べています。

(1) S1 が S2 の適切なサブシーケンスである場合、標準変換シーケンス S1 は標準変換シーケンス S2 よりも優れた変換シーケンスです (左辺値変換を除いて、13.3.3.1.1 で定義された標準形式の変換シーケンスを比較すると、恒等変換シーケンスは、任意の非恒等変換シーケンスのサブシーケンスと見なされます) ...

テンプレート バージョンの変換は、実際には非テンプレート バージョンの適切なサブセット(資格変換) (資格および配列からポインターへの変換) であり、適切なサブセットはコストが低いと見なされます。

したがって、最初の 2 つのケースではテンプレート バージョンが優先されます。3 番目のケースでは、非テンプレート バージョンの配列からポインターへの変換とテンプレート バージョンの修飾のみが変換されるため、どちらの方向にもサブセットはなく、上記のルールに基づいて非テンプレート バージョンが優先されます。 、ランキング表の下)。

于 2012-08-01T04:04:10.730 に答える