2017-06-29 4 views
6

混乱を避けるために、配列とポインタの違い、ポインタの崩壊の概念、配列の受け渡しの概念をなど、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に必要とする関数をコンパイラが考慮する理由を理解したいと思います。

答えて

4

the first overload matches the type exactly, whereas the second overload requires an extra decay-to-pointer step.

overload resolutionranking of implicit conversion sequencesを確認する際、array-to-pointer conversionが完全一致とみなされるので、これ第二過負荷が第一1と同じランクを持っています。標準から

$16.3.3.1.1 Standard conversion sequences [over.ics.scs] Table 13 — Conversions

Conversion     Category    Rank   Subclause 
No conversions required  Identity    Exact Match 
... ... 
Array-to-pointer conversion Lvalue Transformation Exact Match [conv.array] 
... ... 

それは、「不要な変換」のランク(第一過負荷のために、すなわちケース)があまりにも「完全に一致」であることは注目に値します。

関連する問題