c++ - La conversión es ambigua en Visual Studio 2015, pero no con clang
visual-studio-2015 (2)
No he podido encontrar ninguna referencia que documente que la implementación de Visual C ++ intencionalmente se desvía del estándar en este sentido.
Aquí tienes: Advertencia del compilador (nivel 1) C4928 . El mensaje es
inicialización de copia ilegal; Se ha aplicado implícitamente más de una conversión definida por el usuario
También dice esto:
El compilador ejecutó el código en todas esas rutinas.
Entonces, hay una extensión de lenguaje de facto que Microsoft apenas ha documentado.
Puede usar el argumento de línea de comando /we4928
para convertir la advertencia en un error, eliminando efectivamente esta única extensión. Vea here para estos argumentos.
El siguiente código, una versión simplificada del código que se encuentra en el proyecto de googlemock, no se compila en Visual Studio 2015 Update 1, pero se compila en clang [Apple LLVM versión 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;
}
El error ocurre en el asignación declaración
Matcher<ConvertibleFromAny> m = em;
y el mensaje de error es
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
Puedo ver ingenuamente una ambigüedad entre una llamada de miembro a
EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()
y una inicialización conceptualmente similar a
Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))
Supongo que clang descarta la segunda opción.
EDITAR: Inspirado por el comentario de TC, probé lo siguiente:
struct A
{
};
struct X
{
X(const A&);
};
struct B
{
B(const X&);
};
int main()
{
A a;
B b = a;
}
Se compila con VS 2015, pero no con clang. No he podido encontrar ninguna referencia que documente que la implementación de Visual C ++ intencionalmente se desvía del estándar en este sentido.
¿Es este un problema bien conocido?
Ambos ejemplos de código producen el resultado esperado con la actualización 1 de VS2015, si habilito el indicador "Deshabilitar extensiones de idioma" ( /Za
). Es decir, el primero compila, el segundo no.
Sin embargo, no estoy seguro de qué extensión en particular está interfiriendo aquí. Encontré esta página de MSDN: Extensiones de Microsoft para C y C ++ , pero no parece estar completa; por ejemplo, no se menciona el enlace de una T no const a un valor r.