2016-10-07 12 views
3

次の例をコンパイルする際に奇妙な問題があります。私はfoo<short>(0)を呼び出すときに、foo<int>(0)コンパイルを呼び出しますが、0のテンプレート関数のあいまいなパラメータの控除

template<typename T> 
struct identity { 
    typedef T type; 
}; 

template<typename T> 
void foo(typename identity<T>::type v) {} 

template<typename T> 
void foo(typename identity<T>::type* v) {} 

int main() { 
    foo<int>(0); 
    foo<short>(0); 
    return 0; 
} 

0が値またはポインタである場合、コンパイラは推測することはできません。私は、アイデンティティを使用してテンプレートパラメータの明示的な指定を強制します。コンパイラ(msvc)エラーメッセージ:

error C2668: 'foo': ambiguous call to overloaded function 

コンパイラのバグですか?

答えて

3

コンパイラのバグです。これは、0をポインタ型に変換すると「変換ランク」があるためです。

C++ 11§4.10(変換ランク)

ヌルポインタ定数は値ゼロ またはタイプSTDのprvalue有する整数リテラル(2.13.2):: nullptr_tあります。ヌルポインタ定数は をポインタ型に変換できます。結果はそのタイプのnullポインタ値 であり、オブジェクトの他のすべての値と区別されます ポインタまたは関数ポインタ型。そのような変換はヌル ポインタ変換と呼ばれます。

ですから、リテラル0をライトしたとき、および変換コンパイラは同様のランクの2つのオーバーロードに遭遇、必要である - 一つの非ポインタ型、および他のポインタ型を。

いくつかのより多くの例:

foo<short>((short)0); // No conversion necessary: allowed 
foo<nullptr_t>(nullptr); // No conversion necessary: allowed 
foo<nullptr_t>(0); // ambiguous 
foo<nullptr_t>(NULL); // ambigious - another reason to stop using NULL 
関連する問題