2011-06-23 4 views
7

次のコードは、g ++ 4.1.2およびg ++ 4.4.4でコンパイルされました。どちらもコメントに記載されている結果を示します。非constポインタを持つ関数を呼び出すと、constへのポインタを取る関数上のテンプレート関数に戻ります

int f(const int * a) 
{ 
    return 0; 
} 

template<typename A> 
int f(A a) 
{ 
    return 1; 
} 

int main() 
{ 
    int x; 
    // return f(&x); // returns 1 
    return f((const int *)&x); // returns 0 
} 

その代わり、期待f(const int *)f<int *>(int *)に解決f(int *)のコールに煮詰めるように見えます。私はこれが衝撃的で、まったく直感的ではないことを発見しました。

これはg ++のバグか、C++の暗いコーナーか、なんらかの理由で明白ですか?それがバグでなければ、その背後にある理論や論理はなんですか?この問題に関する安全対策はありますか?

+0

ANSI C++コンパイラに関する限り、 'f(int)'と 'f(const int)'は同じプロトタイプです – sehe

+1

'f(int *)'は 'f(const int * )/ f(int const *) ' – Roland

+0

おそらく。 Link:http://stackoverflow.com/questions/2121525/const-pointers-in-overload-resolution/2121616#2121616 – sehe

答えて

4

なぜ、f(&x)コールの場合、関数のconstバージョンを "expected"と呼んでいますか?

あなたがすでに知っているように、引数タイプはint *です。そのため、関数のf(int *)バージョンは、f(const int *)バージョンよりもよく一致します。これは、前者では、引数タイプがと正確にはに一致するためです。コンパイラはテンプレートからf(int *)を生成する機会を見て、その機会に恵まれる。これはC++での動作です。

テンプレートのバージョンが非テンプレートのものと同じくらい良い場合は、非テンプレートのものが通常勝ちます。しかし、テンプレートバージョンが明らかに優れているこのケースでは、テンプレートバージョンが勝ちます。

明らかに、コンパイラが非テンプレートバージョンの関数を選択することを期待していました。どうして?インスタンス化されたテンプレートf<int *>については

+0

私は些細で暗黙のconst変換のために勝つことを期待しました。ポインタの型をアップグレードするconstは、テンプレートを検討する前に常に起こるということは、私にはうまく思えます。おそらく、なぜそれが良い考えではないかという例があります。 – Roland

+4

@Roland:変換なし>過負荷分解能では些細な変換。 – ildjarn

+0

@Roland:操作を実行する2つの方法があると想像してください。それは(その議論に関して)破壊的です。したがって、 'const'バージョンでは、最初に引数のコピーを実行する必要があります。これは明らかに効率が悪いことです。例: 'T && operator +(T &&、T const&)'は 'T operator +(T const&、T const&)'よりも効率的です。 –

8

変換なし(int * - >const int *)は、それがより良い試合ですので、必要とされている - 実際には、それだけのために何が起こるかである非テンプレート完全一致、反対失うことになる完全一致、です2回目の呼び出し。

「よりよくマッチする」ルールの完全な説明は、C++標準の13.3.3で利用できます。

関連する問題