2017-06-29 6 views
6

Pour éviter toute confusion, je comprends très bien la différence entre les tableaux et les pointeurs, le concept de désintégration et le concept de passage d'un tableau par référence en C++, etc.Règles de liaison d'argument de fonction pour passer un tableau par référence vs passant pointeur

Ma question ici est spécifiquement sur les règles utilisées par le compilateur pour sélectionner une fonction à partir d'un ensemble de fonction surcharge candidats, quand on surcharge prend une référence de tableau, et l'autre la surcharge prend un pointeur.

Par exemple, supposons que nous avons:

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; 
} 

Si nous essayons d'invoquer modèle de fonction foo() comme suit:

const char arr[2] = "A"; 
foo(arr); 

... alors mes attentes serait que le premier surcharge, celle qui prend une référence de tableau, serait sélectionnée par le compilateur.

Cependant, en utilisant GCC 4.9.2, si je compilez le code ci-dessus, je reçois une erreur:

test.cpp:28:9: error: call of overloaded ‘foo(const char [2])’ is ambiguous 

On ne sait pas bien pourquoi les deux sont considérés comme des candidats surcharges tout aussi bien par le compilateur ici, depuis le la première surcharge correspond exactement au type, tandis que la seconde surcharge nécessite une étape supplémentaire de décroissance-à-pointeur.

Maintenant, je suis en mesure d'obtenir la surcharge de travail ci-dessus en utilisant explicitement type_traits comme suit:

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; 
} 

Dans ce cas, le programme et compile la surcharge qui prend une référence de tableau est sélectionné. Cependant, je ne comprends pas pourquoi cette solution devrait être nécessaire. Je voudrais comprendre pourquoi le compilateur considère une fonction qui nécessite de decay-to-pointer un candidat de surcharge tout aussi probable que la référence de tableau, quand l'argument passé est vraiment un tableau.

Répondre

4

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

Parce que lors de la vérification du ranking of implicit conversion sequences dans overload resolution, le array-to-pointer conversion est considéré comme une correspondance exacte, donc la 2e surcharge a le même rang que la 1ère.

de la norme, $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] 
... ... 

Il convient de noter que le rang de « Aucune conversion nécessaire » (à savoir le cas pour la 1ère surcharge) est « Exact Match » aussi.