Comment comparer deux séquences de conversion standard en utilisant le rang des conversions contenues
#include <iostream>
void g(int*); //#1
void g(int (&arr)[2]); //#2
void f(int*); //#3
void f(int const*); //#4
int main(){
int arr[2] ={0};
f(arr); // choose #3
g(arr); //ambiguous
}
Considérez le code ci-dessus, # 3 est sélectionné pour f(ptr)
, cependant, g(arr)
donne un ambiguous
diagnostic.
La règle de choix de la meilleure fonction est définie comme suit:
La séquence de conversion standard S1 est une meilleure séquence de conversion que la séquence de conversion standard S2 si
- S1 est une sous-séquence propre de S2 (en comparant les séquences de conversion sous la forme canonique définie par [over.ics.scs], à l'exclusion de toute transformation Lvalue; la séquence de conversion d'identité est considérée comme une sous-séquence de toute séquence de conversion sans identité ) ou , sinon ça
Alors jetez un œil à over.ics.scs # 3
Ceux-ci sont utilisés pour classer les séquences de conversion standard. Le rang d'une séquence de conversion est déterminé en considérant le rang de chaque conversion dans la séquence et le rang de toute liaison de référence.
Selon ma compréhension de la règle ci-dessus, je peux comprendre pourquoi #3
est la meilleure surcharge pour f(ptr)
, c'est-à-dire:
Étant donné S1 comme (arr => int *):
Array-to-pointer conversion -> (identity conversion)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
tandis que S2 est donné comme (ptr => int const *)
Array-to-pointer conversion -> Qualification conversions -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int const* int const* => int const*
Puisque identity conversion
est une sous-séquence propre de Qualification conversions
, donc S1 est meilleur que S2. Ainsi, # 3 est sélectionné par résolution de surcharge pour f(ptr)
.
Lorsque j'utilise un processus similaire pour déterminer celui qui convient le mieux g(arr)
, je rencontre un problème.
Encore une fois, étant donné S1 comme (arr => int *)
Array-to-pointer conversion -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
tandis que S2 est donné comme (arr => int (& arr) [2])
Lorsqu'un paramètre de type référence se lie directement à une expression d'argument, la séquence de conversion implicite est la conversion d'identité, sauf si l'expression d'argument a un type qui est une classe dérivée du type de paramètre, auquel cas la séquence de conversion implicite est un dérivé. conversion en base
identity conversion
^^^^^^^^^^^^^^^^^^^
bind to reference
Ici, identity conversion
of S2
est une sous-séquence propre de Array-to-pointer conversion
of S1
, donc il devrait être mieux que S1
, pourquoi le compilateur se plaint g(arr)
est une invocation ambiguë?
Dois-je mal interpréter la façon de classer les séquences de conversion standard? Comment comparer deux ICS standards (rang de la conversion contenue)?
Réponses
Le point clé est ici:
S1 est une sous-séquence propre de S2 (en comparant les séquences de conversion sous la forme canonique définie par [over.ics.scs], à l' exclusion de toute transformation Lvalue ; la séquence de conversion d'identité est considérée comme une sous-séquence de toute séquence de conversion sans identité) ou , sinon ça
Cela signifie que, pour l'appel de fonction g(arr)
, toutes les conversions de tableau en pointeur ne sont pas utilisées pour déterminer le rang. En d'autres termes, d'un type int[2]
à l'autre int*
, il n'y a qu'une conversion d'identité qui sert à déterminer le rang. Par conséquent, S1 de void g(int*);
et S2 de void g(int (&arr)[2]);
sont des ICS indiscernables, d'où le compilateur donne une erreur ambiguë.
En revanche, les conversions void f(int*);
et void f(int const*);
utilisé pour comparer le rang sont identity conversion
et qualification conversion
, respectivement.
Selon la règle:
la séquence de conversion d'identité est considérée comme une sous-séquence de toute séquence de conversion sans identité
Par conséquent, Qualification conversion
est considéré comme ayant un rang pire que celui de identity conversion
. Alors, a void f(int*)
remporté la compétition.
Vous essayez d'appliquer over.ics.rank-3.2.1 à ces ensembles de surcharge, mais cette règle ne s'applique ni à f
ni g
.
Étant donné l'appel f(arr);
, lors de l'exécution de la résolution de surcharge pour f
, les deux surcharges nécessitent une séquence de conversion standard consistant en une conversion de tableau en pointeur , et les deux ont le même rang, ce qui correspond à la correspondance exacte . Le bris d'égalité utilisé dans ce cas est over.match.best # over.ics.rank-3.2.5 :
La séquence de conversion standard S1 est une meilleure séquence de conversion que la séquence de conversion standard S2 si
...
S1 et S2 ne diffèrent que par leur conversion de qualification ([conv.qual]) et donnent des types similaires T1 et T2, respectivement, où T1 peut être converti en T2 par une conversion de qualification.
Il y a un exemple suivant cette règle qui montre comment la règle fonctionne.
Pour l'ensemble de surcharge f
, T1
est int *
et T2
est int const *
, et T1
peut être converti T2
par une conversion de qualification.
Dans le cas de l'appel g(arr);
, lors de l'exécution de la résolution de surcharge, la surcharge g(int (&)[2])
est classée comme correspondance exacte , car la séquence de conversion standard nécessaire est une non conversion requise .
Cependant, la surcharge g(int*)
est également classée comme correspondance exacte , car la séquence de conversion standard nécessaire est une conversion tableau en pointeur .
Contrairement à pour f
cependant, il n'y a pas de règle dans [over.ics.rank] qui élimine l'ambiguïté entre les séquences de conversion standard pour g
, et l'appel échoue.