none
テンプレートのオーバーロード解決 RRS feed

  • 質問

  • 別スレッドで試しに作ったサンプルの動作が予想外だったので質問します。


    例えば、以下のような2つの関数があって、

     

    Code Snippet

    void Func(char* ptr) {
        TRACE("Func(char* ptr) was called\n");
    }


    template <size_t N>
    void Func(char (&buffer)[N]) {
        TRACE("Func(char (&buffer)[N]) was called\n");
    }

     

    Func を次のように呼び出すと、

     

    Code Snippet

    char buf[1024];

    Func(buf);

     

    VS2005 ではテンプレートではない方の Func が呼び出されました。


    buf は配列なので、この場合はテンプレート版の方が断然有利、というより、完全一致のインスタンスが生成されると思うのですが、ここでテンプレート版でない方が呼ばれるのは何故なのでしょうか?

    2008年4月23日 16:24

回答

  • C++ の International Standard (ISO/IEC 14882:1998) によると、この場合はテンプレートでない方の Func が呼び出されるようです。
    (つまり、VS2005 の動作は正しい。)


    まず、問題を簡単にするために、テンプレートでない関数のオーバーロード解決を考えてみます。

    Code Snippet

    void Func(char* ptr) {} // *1
    void Func(char (&buffer)[1024]) {} // *2

    void F() {
        char buf[1024];
        Func(buf); // error: ambiguous!
    }



    この場合、buf の型が *2 の引数とピッタリ一致しているにも関わらず、「*1 と *2 のどちらにしたらよいか分からない」といった感じのエラーになります。
    (VS2005 では error C2668 になりました。)
    これは、以下の弱型変換も厳密一致とみなされるためです。(IS 13.3.3.1.1 Standard conversion sequences, Table 9 より)

    1. Lvalue-to-rvalue conversion (lvalue から rvalue への変換)
    2. Array-to-pointer conversion (配列からポインタへの変換)
    3. Function-to-pointer conversion (関数からポインタへの変換)
    4. Qualification conversions (修飾子変換)

    この場合は 2 の配列からポインタへの変換と、配列へのリファレンスが共に厳密一致となっているわけです。


    次に、問題のテンプレートの場合を考えます。

    Code Snippet

    void Func(char* ptr) {} // *1
    template <size_t N> void Func(char (&buffer)[N]) {} // *3



    ここで、Func(buf) のオーバーロードを解決するために、*3 は次のような関数としてインスタンス化されます。

    Code Snippet

    template <> void Func(char (&buffer)[1024]) {} // *4



    つまり、*1 と *4 の対決です。
    先ほどの *1 と *2 の対決では引き分けとなってしまいましたが、今回は *4 がテンプレートという点が異なります。
    そして、14.8.3 Overload resolution の脚注(133)に以下のような記述があります。

    Note also that 13.3.3 specifies that a nontemplate function will be given preference over a template
    specialization if the two functions are otherwise equally good candidates for an overload match.
    「それから 13.3.3 でも言ってるけど、2つの関数が同じくらいの強さならテンプレートじゃない方が強いよ(超簡訳 by zakio)」

    で、13.3.3 Best Viable Function をみると、やはり関数 F1 の方が 関数 F2 より強くなる条件の1つに、

    - F1 is a nontemplate function and F2 is a template function specialization,

    とあり、テンプレートでない方が強いことがはっきりと記されています。


    以上、ピッタリ一致しているはずの *4 が負けてしまうという(私にとって)直感的でない動作は、私なりに標準を解釈した結果「仕様どおり」ということで落ち着きそうです。

    # しばらく様子を見て回答済みにしたいと思います。
    # ツッコミは大歓迎です。

    2008年5月1日 14:08