2012-03-28 19 views
6

Ho il seguente pezzo di codice:errore Clang: conversione ambiguo 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 segnala il seguente errore:

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. 

non riesco a capire perché è il compilatore genera un errore anche se ho definito l'operatore di conversione e faccio esplicita la conversione in quel posto specifico usando static_cast <>. Il codice passa la compilazione con i compilatori GCC 4.5.2 e Visual Studio 2008. La versione Clang è 3.1, creata da me stesso dai repository git di Clang e LLVM un paio di giorni fa.

Quindi, Clang segnala un errore effettivo? E se sì, perché è un errore dato che è per nulla ovvio (non chiederò perché gli altri compilatori non ne parlano)?

UPDATE: il codice di esempio è ora un piccolo esempio compilabile (mi dispiace di non farlo dalla prima volta) e di replicare la situazione reale che ho. Sembra che l'operatore di conversione di AliasA sia il problema, perché se viene rimosso allora tutto si compila bene. La cosa sgradevole in questo momento è che per il codice di cui sopra ottengo errori anche da GCC.

UPDATE 2: ho aggiunto del codice al campione per riflettere meglio la mia situazione reale; l'unica differenza è che per il campione sopra ho anche un errore da GCC, mentre per il mio vero codice non lo faccio.

+1

Puoi mostrare la dichiarazione di 'someFunc'? –

+0

Probabilmente è necessario mostrare più codice per capire la risposta (un piccolo esempio compilabile sarebbe il migliore). –

+0

Qual è la dichiarazione di AliasB? –

risposta

0

Penso di aver capito in parte cosa sta succedendo, ma non credo di comprendere l'intera situazione. Così i percorsi di conversioni il compilatore vede apparire come di seguito:

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

Quindi ha senso e il compilatore è proprio nel riportare l'ambiguità (amo errore clan'g e messaggi di avviso). Un modo per farlo funzionare è interrompere il percorso di conversione tramite AliasA (vedere i commenti contrassegnati con (*) nel codice di esempio nella domanda).Funziona anche se interrompo l'espressione offendente e faccio affidamento solo sulla conversione implicita, non provando a esplicitamente static_cast <> qualsiasi cosa (vedere i commenti contrassegnati con (**) nel codice di esempio nella domanda). Ma non capisco completamente cosa sta succedendo dietro le quinte. Non riesco ancora a capire perché si comporta in modo diverso nel caso (**) perché i percorsi di conversione sembrano uguali, almeno per la parte "theB.combine (high())".

3

Ci sono due modi per static_cast per convertire una A in B:

  1. uso A::operator B e chiamare il costruttore di copia implicita B::B(const B& value) per creare il nuovo B

  2. uso A::operator AliasA, convertire il risultato per AliasB e chiamare B::B(const AliasB& value)

Il comp iler non sa da che parte preferire. Si può dare un suggerimento per utilizzare la seconda opzione scrivendo:

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

Per utilizzare la prima opzione è possibile omettere il cast semplicemente scrivendo:

someFunc(counter, someA); 

Beh, non sono sicuro se il quest'ultimo è un comportamento ben definito, ma funziona almeno con gcc e msvc.

3

Ho archiviato un bug report su questo a clang. Sostengono che non è un bug. Lo standard C++ non ha una specifica per questo caso e quindi il compilatore lo segnala come ambiguo. Vedi bug report.

Penso che questo comportamento sia contro-intuitivo. Il primo percorso attraverso A :: operator B() è una corrispondenza perfetta, mentre il secondo percorso prevede tre conversioni di tipo. L'unica cosa logica da fare è considerare la corrispondenza perfetta come superiore.

Cosa dovrebbe fare un compilatore quando un caso non viene risolto esplicitamente nello standard C++?

  1. un messaggio di errore
  2. fare una scelta logica per analogia ad altre norme
  3. contattare il Comitato standard C++ e dire loro di rivedere la norma.

?