2

私は2つの機能を持っています:

void foo(const char * p)

template<size_t T_Size>
void foo(const char (& p)[T_Size]) ;

呼び出しを考えると:

int main(int argc, char* argv[])
{
   char a[21] ;                          // typeid : A21_c
   sprintf(a, "a[21] : Hello World") ;

   const char * b = "b : Hello World" ;  // typeid : PKc

   // note that literal "liter. : Hello World" has a typeid : A21_c

   foo(a) ;                      // calls foo(const char (& p)[T_Size])
   foo(b) ;                      // calls foo(const char * p)
   foo("liter. : Hello World") ; // calls foo(const char * p) ???

   return 0 ;
}

どうやら、fooスタックベースの正しく宣言された配列での呼び出しは期待どおりに動作しますfooが、リテラル "liter. : Hello World" での呼び出しはそうではありません。

1 つのオーバーロードを他のオーバーロードよりも選択するために、シンボル ルックアップが従う規則は正確には何ですか?

宣言された配列と文字列リテラルの動作が異なるのはなぜですか?

ありがとう !

編集

目的の結果を得る (つまり、リテラル文字列をfoo(const char (& p)[T_Size])関数に一致させる) 方法は、を削除してvoid foo(const char *p)代わりに追加することです。

struct FooIndirect
{
    const char * m_p ;
    FooIndirect(const char *p) : m_p(p) {}
} ;

void foo(const FooIndirect & p)
{
    // do something with p.m_p
}

この間接化により、テンプレート化された foo は文字列リテラルにより適したものになり、ユーザーは引き続きポインターを使用できます (間接化は最適化されたコンパイル モードで削除されます)。

g++ 4.4.3 でテストしましたが、すべてのコンパイラで同じように動作すると思います。

4

2 に答える 2

4

規格の第 13 章 (過負荷の解決) の表 9 では、「配列からポインターへ」の変換 (非テンプレートの場合) が「変換不要」 (テンプレート バージョンの場合) と同じランク (EXACT MATCH) になるようにランク付けされています。

他のすべてが同じであれば、非テンプレート バージョンがテンプレート バージョンより優先されます。

于 2010-08-19T13:32:41.157 に答える
1

テンプレート化された関数と比較して利用可能な場合、コンパイラーは常にテンプレート化されていないオーバーロードを呼び出します。テンプレート化されていない完全に適切なオーバーロードを提供したので、コンパイラーはそれを呼び出します。

于 2010-08-19T13:23:04.403 に答える