14
programma

Il seguente C++ compila senza avvisi a tutti i compilatori che ho provato (GCC 4.6.3, LLVM 3.0, ICC 13.1.1, SolarisStudio 12.1/12.3):Diversi operatori di fusione utilizzate da diversi compilatori

struct CClass 
{ 
    template<class T> 
    operator T() const { return 1; } 

    operator int() const { return 2; } 
}; 

int main(void) 
{ 
    CClass x; 
    return static_cast<char>(x); 
} 

Tuttavia, tutti tranne i compilatori SolarisStudio restituiscono 2, SolarisStudio (versione) restituisce 1, che considererei il risultato più logico.

Utilizzando return x.operator char(); risultati in tutti i compilatori ritorno 1.

Ovviamente, dal momento che per capire questo fuori, ho utilizzato la seconda notazione. Tuttavia, mi piacerebbe sapere quale compilatore è corretto e perché. (Si potrebbe pensare che regole di maggioranza, ma questo ancora non spiega il motivo per cui .)

Questa domanda sembra essere correlato alle domande in modo here, here e here, ma questi "solo" dare soluzioni a problemi, senza spiegazioni (che sono stato in grado di applicare comunque al mio particolare problema).

Si noti che aggiungendo un operatore di colata sovraccarico aggiuntivo, ad esempio i risultati in tutti i compilatori eccetto SolarisStudio lamentandosi dell'ambiguità.

+0

Appena testato nel mio compilatore, G ++ 4.8.0, e restituisce 1. – rodrigo

+1

G ++ 4.7.2 restituisce anche 1. E con 'operator float()', non vi è alcun reclamo in merito a qualsiasi ambiguità. – hvd

+2

g ++ ne restituisce uno a partire da 4.7 http://gcc.godbolt.org/ – Riga

risposta

9

Il primo (modello) sovraccarico deve essere prelevato.

Paragrafo 13.3.3/1 delle C++ 11 specifica standard:

[...] una funzione valida F1 è definita come una funzione migliore di un'altra funzione vitale F2 se per tutti gli argomenti i, ICSi(F1) non è una sequenza di conversione peggio di ICSi(F2), e quindi

- per qualche argomento j, ICSj(F1) è una migliore sequenza di conversione di.210, o, se non che,

- contesto è un'inizializzazione mediante conversione definita dall'utente (vedere 8.5, 13.3.1.5 e 13.3.1.6) e la sequenza conversione standard dal tipo di ritorno F1 al tipo di destinazione (cioè, il tipo di entità inizializzato) è in una sequenza di conversione della sequenza di conversione standard da il tipo di ritorno di F2 al tipo di destinazione.[Esempio:

struct A { 
    A(); 
    operator int(); 
    operator double(); 
} a; 
int i = a; // a.operator int() followed by no conversion 
      // is better than a.operator double() followed by 
      // a conversion to int 
float x = a; // ambiguous: both possibilities require conversions, 
      // and neither is better than the other 

- fine esempio] o, se non quella,

- F1 è una funzione non-template e F2 è un modello di specializzazione funzione, o, se non che,

[...]

Come si può vedere il, fatto che il primo operatore di conversione è un modello diventa rilevante solo quando la sequenza di conversione standard dal suo tipo di ritorno (char, in questo caso) per il tipo di destinazione (char, in questo caso) non è migliore della sequenza di conversione standard dal tipo di ritorno del sovraccarico non di modello (int, in questo caso) al tipo di destinazione (char, in questo caso).

Tuttavia, una conversione standard da char a char è un corrispondenza esatta, mentre una conversione standard da int a char non lo è. Pertanto, il terzo elemento del § 13.3.3/1 non si applica e il secondo elemento lo fa.

Ciò significa che il primo (modello) sovraccarico deve essere prelevato.

+0

Non proprio. Dice che un modello ** specializzazione ** verrà scelto per questo. Ma nel caso dell'op non c'è specializzazione. Il compilatore non inizierà nemmeno a creare un modello, perché ha già trovato una fusione non stampata che può essere utilizzata. I modelli vengono creati solo se vengono chiamati esplicitamente o non c'è altro sovraccarico corrispondente. Non c'è motivo per il compilatore di iniziare a "indovinare" su un modello corrispondente –

+0

@YochaiTimmer: No, non è vero. Non istanzia il modello, ma eseguirà la deduzione degli argomenti del modello e verificherà se il modello è un candidato valido per la risoluzione del sovraccarico. Se questo risulta essere il candidato migliore * migliore *, lo sceglierà e lo istanzia –

5

Il primo è una corrispondenza esatta, il secondo richiede una conversione. Le corrispondenze esatte hanno la priorità sulle conversioni.

Queste altre domande che hai collegato sono per lo più estranee al tuo.

Alcuni consigli: non utilizzare operatori di conversione modelli. Chiamalo invece convert_to.

+1

+1 uno per gli avvisi sugli operatori di conversione dei modelli. Forse potresti aggiungere qualche spiegazione sul perché questo è pericoloso. – Walter