Considérez ce code:
#include <vector>
#include <iostream>
enum class A
{
X, Y
};
struct Test
{
Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
{ std::cout << "vector overload" << std::endl; }
Test(const std::vector<double>&, int, A = A::X)
{ std::cout << "int overload" << std::endl; }
};
int main()
{
std::vector<double> v;
Test t1(v);
Test t2(v, {}, A::X);
}
Cela imprime:
vector overload
int overload
Pourquoi cela ne produit-il pas une erreur de compilation en raison d'une résolution de surcharge ambiguë? Si le deuxième constructeur est supprimé, nous obtenons vector overload
deux fois. Comment / selon quelle métrique est int
une correspondance sans ambiguïté meilleure {}
que std::vector<int>
?
La signature du constructeur peut sûrement être coupée plus loin, mais je viens d'être piégé par un morceau de code équivalent et je veux m'assurer que rien d'important n'est perdu pour cette question.
c++
language-lawyer
overload-resolution
Max Langhof
la source
la source
{}
comme un bloc de code, assigne 0 aux variables - exemple: const char x = {}; est mis à 0 (caractère nul), même pour int etc.{}
effectivement dans certains cas particuliers, mais ce n'est généralement pas correct (pour commencer,std::vector<int> x = {};
fonctionne,std::vector <int> x = 0;
non). Ce n'est pas aussi simple que «{}
attribue zéro».struct A { int x = 5; }; A a = {};
n'affecte aucun zéro, il construit unA
aveca.x = 5
. C'est différentA a = { 0 };
, qui s'initialisea.x
à 0. Le zéro n'est pas inhérent à{}
, il est inhérent à la façon dont chaque type est construit par défaut ou initialisé en valeur. Voyez ici , ici et ici .Réponses:
C'est dans [over.ics.list] , c'est moi qui souligne
Le
std::vector
est initialisé par le constructeur et la puce en gras le considère comme une conversion définie par l'utilisateur. Pendant ce temps, pour unint
, c'est la conversion d'identité, donc elle l'emporte sur le rang du premier c'tor.la source
0
a du typeint
mais pas du typestd::vector<int>
, comment est-ce un "comme si" écrit à la nature "non typé" de{}
?std::vector<int>
. Comme vous l'avez dit, je m'attendais à ce que "le type du paramètre finisse par décider quel est le type de l'argument", et un{}
"de type" (pour ainsi dire)std::vector<int>
ne devrait pas avoir besoin de conversion (sans identité) pour initialiser astd::vector<int>
. La norme dit évidemment que c'est le cas, c'est donc ça, mais cela n'a pas de sens pour moi. (Attention, je ne prétends pas que vous ou la norme avez tort, essayez simplement de concilier cela avec mes modèles mentaux.)