混乱を避けるために、配列とポインタの違い、ポインタの崩壊の概念、配列の受け渡しの概念をなど、C++でを参照配列を参照渡しに渡すための関数の引数バインディング規則
私の質問は、ここでは、具体的1つの過負荷が配列参照を取る関数過負荷候補の集合から機能を選択するために、コンパイラで使用されるルールについて、および他のですoverloadはポインタをとります。例えば
、我々が持っているとします
template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
std::cout << "Array-reference overload!" << std::endl;
}
template <class T>
void foo(const T* ptr)
{
std::cout << "Pointer overload!" << std::endl;
}
我々は次のように関数テンプレートfoo()
を起動しようとすると:
const char arr[2] = "A";
foo(arr);
を...その後、私の期待は最初ということでしょうオーバーロードは、配列参照を取るもので、コンパイラによって選択されます。
test.cpp:28:9: error: call of overloaded ‘foo(const char [2])’ is ambiguous
両方のオーバーロードがあるため、ここでは、コンパイラによって同様に良好な候補と考えられている理由は、私には不明だ:私は上記のコードをコンパイルする場合、私はエラーを取得するGCC 4.9.2を使用して、しかし
、最初のオーバーロードは型に正確に一致しますが、2回目のオーバーロードでは余分なディケイ・ツー・ポインター・ステップが必要です。
は今、私は次のように明示的にtype_traits
を使用することにより作業上の過負荷を取得することができています:この場合
template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
std::cout << "Array-reference overload!" << std::endl;
}
template <class T>
void foo(T ptr, typename std::enable_if<std::is_pointer<T>::value>::type* = 0)
{
std::cout << "Pointer overload!" << std::endl;
}
は、プログラムがコンパイルされ、配列の参照を受け取るオーバーロードが選択されています。しかし、私はこの解決策がなぜ必要なのか理解していません。私は、引数が非常に多くの配列である場合、配列参照と同様に可能性のあるオーバーロード候補をdecay-to-pointerに必要とする関数をコンパイラが考慮する理由を理解したいと思います。