2012-03-28 8 views
6

tengo el siguiente fragmento de código:error Clang: conversión ambigua para static_cast

typedef int AliasB; 
typedef unsigned short AliasA; 

class Alias 
{ 
public: 
    explicit Alias(int someInt) { } 

}; 

// (*) !! below breaks the conversion path via AliasA !! 
//typedef Alias AliasA; 

class C 
{ 
public: 
    C() { } 
}; 

class B 
{ 
public: 
    B() { } 
    B(const AliasB& value) { } 

    operator AliasB() const 
    { 
     return -1000; 
    } 

    C combine(const B& someB) 
    { 
     return C(); 
    } 
}; 

class A 
{ 
public: 
    A() { } 

    operator B() const 
    { 
     return B(); 
    } 

    operator AliasA() const 
    { 
     return 1001; 
     // (*) !! below breaks the conversion path via AliasA !! 
     //return AliasA(1000); 
    } 

    A high() 
    { 
     return A(); 
    } 
    A low() 
    { 
     return A(); 
    } 

    C process() 
    { 
     return (static_cast<B>(low())).combine(static_cast<B>(high())); 

     // (**) !! the below compiles fine !! 
     //B theB = low(); 
     //return theB.combine(high()); 
    } 
}; 

inline int someFunc(unsigned int someParam, const B& bParam) 
{ 
    return 1; 
} 

inline A createSomeA() 
{ 
    return A(); 
} 

int main() 
{ 
    A someA; 
    unsigned int counter = 200; 
    someFunc(counter, someA); 
    //someFunc(counter, static_cast<B>(createSomeA())); 
    someA.process(); 
    return 0; 
} 

Clang informa del error siguiente:

clang_static_test.cpp:66:17: error: ambiguous conversion for static_cast from 'A' to 'B' 
     return (static_cast<B>(low())).combine(static_cast<B>(high())); 
       ^~~~~~~~~~~~~~~~~~~~~ 
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor 
class B 
    ^
clang_static_test.cpp:25:5: note: candidate constructor 
    B(const AliasB& value) { } 
    ^
clang_static_test.cpp:66:48: error: ambiguous conversion for static_cast from 'A' to 'B' 
     return (static_cast<B>(low())).combine(static_cast<B>(high())); 
               ^~~~~~~~~~~~~~~~~~~~~~ 
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor 
class B 
    ^
clang_static_test.cpp:25:5: note: candidate constructor 
    B(const AliasB& value) { } 
    ^
2 errors generated. 

No puedo entender por qué es el compilador genera una error aunque tengo el operador de conversión definido y hago explícita la conversión en ese lugar específico utilizando static_cast <>. El código pasa la compilación con los compiladores GCC 4.5.2 y Visual Studio 2008. La versión Clang es 3.1, construida por mí mismo desde los repositorios git de Clang y LLVM hace un par de días.

Entonces, ¿Clang informa un error real? Y en caso afirmativo, ¿por qué es un error, ya que es que no me resulta nada obvio (no preguntaré por qué los otros compiladores guardan silencio al respecto)?

ACTUALIZACIÓN: el código de muestra ahora es un pequeño ejemplo compilable (lo siento por no hacer esto desde la primera vez) y la réplica de la situación real que tengo. Parece que el operador de conversión a AliasA es el problema, porque si se elimina, todo se compila correctamente. Lo desagradable en este momento es que para la pieza de código anterior también recibo errores de GCC.

ACTUALIZACIÓN 2: He añadido un código a la muestra para reflejar mejor mi situación real; la única diferencia es que para la muestra anterior también recibo un error de GCC, mientras que para mi código real no.

+1

¿Puedes mostrar la declaración de 'someFunc'? –

+0

Probablemente necesite mostrar más código para descubrir la respuesta (un pequeño ejemplo compilable sería lo mejor). –

+0

¿Cuál es la declaración de AliasB? –

Respuesta

0

Creo que descubrí en parte lo que está sucediendo, pero no creo que comprenda la situación. Por lo que los caminos conversiones del compilador ve parezca a continuación:

   /-------- A --------\ 
       |      | 
       |      | 
       B    AliasA(unsigned short) 
       |      | 
       |      | 
     copy ctor of B   AliasB(int) 
            | 
            | 
          ctor B(const AliasB& value) 

Así que tiene sentido y el compilador está justo en la presentación de informes de la ambigüedad (Me encanta error clan'g y mensajes de advertencia). Una forma de hacerlo funcionar es romper la ruta de conversión a través de AliasA (consulte los comentarios marcados con (*) en el código de muestra de la pregunta).También funciona si rompo la expresión ofensiva y solo confío en la conversión implícita, no intentando explícitamente static_cast <> cualquier cosa (vea los comentarios marcados con (**) en el código de muestra en la pregunta). Pero no entiendo completamente lo que está sucediendo detrás de escena. Todavía no entiendo completamente por qué se comporta diferente en el caso (**) porque las rutas de conversión parecen ser las mismas, al menos para la parte "theB.combine (high())".

3

Hay dos maneras para que static_cast para convertir una A en un B:

  1. uso A::operator B y llamar a la copia implícita constructor B::B(const B& value) para crear el nuevo B

  2. uso A::operator AliasA, convertir el resultado para AliasB y llame al B::B(const AliasB& value)

The comp Iiler no sabe qué camino preferir. Se puede dar una pista a utilizar la segunda opción por la escritura:

someFunc(counter, static_cast<AliasA>(someA)); 

Para utilizar la primera opción se puede omitir el elenco simplemente escribiendo:

someFunc(counter, someA); 

Bueno, no estoy seguro de si el este último es un comportamiento bien definido, pero funciona al menos con gcc y msvc.

3

He enviado un informe de error sobre esto a clang. Ellos argumentan que no es un error. El estándar de C++ carece de una especificación para este caso y, por lo tanto, el compilador lo informa como ambiguo. Ver bug report.

Creo que este comportamiento es contrario a la intuición. La primera ruta a través del operador A :: B() es una combinación perfecta, mientras que la segunda ruta implica tres conversiones de tipo. Lo único lógico que hay que hacer es considerar la pareja perfecta como superior.

¿Qué debe hacer un compilador cuando un caso no se resuelve explícitamente en el estándar de C++?

  1. producir un mensaje de error
  2. hacer una elección lógica por analogía a otras normas
  3. de contacto del comité de estándares de C++ y les digo que revisar la norma.

?