Opérateur de conversion + constructeur de conversion = comportement non intuitif?

Je ne comprends pas pourquoi le code ci-dessous imprime struct Value plutôt int (ce qui implique que le constructeur de la conversion est en train de convertir Value au lieu de int ). (Visual C ++ 2012)

Pourquoi cela arrive-t-il? Pourquoi le compilateur ignore-t-il complètement le constructeur Value(int) ?

 #include  #include  using namespace std; struct Value { Value(int) { } }; struct Convertible { template operator T() const { throw typeid(T).name(); } }; int main() { try { Value w((Convertible())); } catch (char const *s) { cerr << s << endl; } } 

Modifier:

Encore plus bizarre (en ce moment, il s’agit de C ++ 11, sur GCC 4.7.2):

 #include  #include  using namespace std; struct Value { Value(Value const &) = delete; Value(int) { } }; struct Convertible { template operator T() const { throw typeid(T).name(); } }; int main() { try { Value w((Convertible())); } catch (char const *s) { cerr << s << endl; } } 

Qui donne:

 source.cpp: In function 'int main()': source.cpp:21:32: error: call of overloaded 'Value(Convertible)' is ambiguous source.cpp:21:32: note: candidates are: source.cpp:9:3: note: Value::Value(int) source.cpp:8:3: note: Value::Value(const Value&)  

Si le constructeur de la copie est supprimé, alors pourquoi y a-t-il une ambiguïté?!

Dans le premier exemple, Visual Studio est incorrect. l’appel est ambigu. gcc en mode C ++ 03 imprime:

 source.cpp:21:34: error: call of overloaded 'Value(Convertible)' is ambiguous source.cpp:21:34: note: candidates are: source.cpp:9:5: note: Value::Value(int) source.cpp:6:8: note: Value::Value(const Value&) 

Rappelez-vous qu’un constructeur de copie est implicitement défini par défaut. Le paragraphe qui régit est 13.3.1.3 Initialisation par le constructeur [over.match.ctor] :

Lorsque les objects de type classe sont initialisés directement, la […] résolution de surcharge sélectionne le constructeur. Pour l’initialisation directe, les fonctions candidates sont tous les constructeurs de la classe de l’object en cours d’initialisation.

Dans le deuxième exemple, les fonctions supprimées participent également à la résolution de la surcharge; ils n’affectent la compilation qu’une fois les surcharges résolues, lorsqu’un programme qui sélectionne une fonction supprimée est mal formé. L’exemple de motivation dans la norme est celui d’une classe qui ne peut être construite qu’à partir de types à virgule flottante:

 struct onlydouble { onlydouble(std::intmax_t) = delete; onlydouble(double); }; 

J’ai essayé votre code (sur la version Visual Studio uniquement).

Depuis que vous avez une copie intégrée-CTOR, je suppose que votre principal est égal à:

 int main() { try { Value w((struct Value)(Convertible())); } catch (char const *s) { cerr << s << endl; } } 

Le compilateur a choisi d'utiliser votre copie CTOR plutôt que Value (int).

Le changer pour:

 int main() { try { Value w((int)(Convertible())); } catch (char const *s) { cerr << s << endl; } } 

Il a imprimé "int".