J'ai récemment corrigé un bug.
Dans le code suivant, l'une des fonctions surchargées était const et l'autre non. Le problème sera résolu en rendant les deux fonctions const.
Ma question est pourquoi le compilateur ne s'en est plaint que lorsque le paramètre était 0.
#include <iostream>
#include <string>
class CppSyntaxA
{
public:
void f(int i = 0) const { i++; }
void f(const std::string&){}
};
int main()
{
CppSyntaxA a;
a.f(1); // OK
//a.f(0); //error C2666: 'CppSyntaxA::f': 2 overloads have similar conversions
return 0;
}
0
Est spécial en C++. Un pointeur nul a la valeur de 0
Donc C++ permettra la conversion de 0
En un type de pointeur. Cela signifie que lorsque vous appelez
a.f(0);
Vous pourriez appeler void f(int i = 0) const
avec un int
avec la valeur de 0
, Ou vous pourriez appeler void f(const std::string&)
avec un char*
Initialisé à null.
Normalement, la version int
serait meilleure car c'est une correspondance exacte mais dans ce cas, la version int
est const
, donc elle nécessite une "conversion" a
vers un const CppSyntaxA
, où la version std::string
ne nécessite pas une telle conversion mais nécessite une conversion en char*
puis en std::string
. Ceci est considéré comme un changement suffisant dans les deux cas pour être considéré comme une conversion égale et donc ambigu. Faire les deux fonctions const
ou non const
corrigera le problème et la surcharge int
sera choisie car c'est mieux.
Ma question est pourquoi le compilateur ne s'en est plaint que lorsque le paramètre était 0.
Parce que 0 n'est pas seulement un littéral entier, mais c'est aussi un littéral de pointeur nul. 1 n'est pas un littéral de pointeur nul, il n'y a donc aucune ambiguïté.
L'ambiguïté provient du constructeur de conversion implicite de std::string
qui accepte un pointeur sur un caractère comme argument.
Maintenant, la conversion d'identité de int en int serait autrement préférée à la conversion de pointeur en chaîne, mais il existe un autre argument qui implique une conversion: l'argument d'objet implicite. Dans un cas, la conversion est de CppSyntaxA&
à CppSyntaxA&
alors que dans les autres cas c'est CppSyntaxA&
à const CppSyntaxA&
.
Ainsi, une surcharge est préférée en raison d'un argument, et l'autre surcharge est préférée en raison d'un autre argument et il n'y a donc pas de surcharge préférée sans ambiguïté.
Le problème sera résolu en rendant les deux fonctions const.
Si les deux surcharges sont qualifiées const
, alors la séquence de conversion de l'argument objet implicite est identique, et donc l'une des surcharges est sans ambiguïté préférée.