29 votes

La conversion est ambiguë dans Visual Studio 2015, mais pas avec clang

Le code suivant, une version simplifiée du code trouvé dans le projet googlemock, ne parvient pas à compiler dans Visual Studio 2015 Update 1, mais il compile sur clang [Apple LLVM version 7.0.0 (clang-700.1.76)].

struct ConvertibleFromAny
{
    ConvertibleFromAny(int a_value);

    template <typename T>
    ConvertibleFromAny(const T& a_value);
};

template <typename T>
struct Matcher
{
    Matcher(T value);
};

template <typename Rhs>
struct EqMatcher
{
    explicit EqMatcher(const Rhs& rhs);

    template <typename Lhs>
    operator Matcher<Lhs>() const;
};

int main()
{
    EqMatcher<ConvertibleFromAny> em(1);
    Matcher<ConvertibleFromAny> m = em;

    return 0;
}

L'erreur se produit au niveau du affectation déclaration

Matcher<ConvertibleFromAny> m = em;

et le message d'erreur est

error C2440: 'initializing': cannot convert from 'EqMatcher<ConvertibleFromAny>' to 'Matcher<ConvertibleFromAny>'
note: No constructor could take the source type, or constructor overload resolution was ambiguous

Je peux naïvement voir une ambiguïté entre un appel membre à

EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()

et une initialisation conceptuellement similaire à

Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))

Je pense que Clang exclut la deuxième option.

EDIT : Inspiré par le commentaire de T.C., j'ai testé ce qui suit :

struct A
{
};

struct X
{
    X(const A&);
};

struct B
{
    B(const X&);
};

int main()
{
    A a;

    B b = a;
}

Il compile avec VS 2015, mais pas avec clang. Je n'ai pas été en mesure de trouver des références qui documentent que l'implémentation de Visual C++ s'écarte intentionnellement de la norme à cet égard.

Est-ce un problème bien connu ?

10voto

melak47 Points 969

Vos deux échantillons de code produisent le résultat attendu avec VS2015 Update 1, si j'active l'option "Disable Language Extensions" ( /Za ) drapeau. C'est-à-dire que le premier compile, le second non.

Je ne suis pas sûr. dont L'extension en particulier interfère ici, cependant. J'ai trouvé cette page MSDN : Extensions Microsoft à C et C++ mais il ne semble pas être complet - par exemple, la liaison d'un T& non-const à une rvalue n'est pas mentionnée.

5voto

eh9 Points 3804

Je n'ai pas été en mesure de trouver des références qui documentent que la Visual C++ s'écarte intentionnellement de la norme à cet égard. cet égard.

Voilà : Avertissement du compilateur (niveau 1) C4928 . Le message est

initialisation de copie illégale ; plus d'une conversion définie par l'utilisateur a été implicitement appliquée

Il également dit ceci :

Le compilateur a exécuté le code dans toutes ces routines.

Donc il y a un de facto une extension du langage que Microsoft n'a qu'à peine documentée.

Vous pouvez utiliser l'argument de ligne de commande /we4928 pour convertir l'avertissement en erreur, en supprimant effectivement cette seule extension. Voir aquí pour ces arguments.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X