2015-02-25 35 views
9

stavo giocando con un po 'di codice inutile per comprendere l'inizializzazione di riferimenti membri, e sono imbattuto in questo:inizializzazione di membro di riferimento const nella lista di inizializzazione

struct A {}; 

struct B 
{ 
    B() : a() 
    { 
    } 

    const A& a; 
}; 

Il codice di cui sopra dà il seguente errore quando si compila con gcc 4.9. 2:

In constructor 'B::B()': 
error: value-initialization of reference type 'const A&' 
    B() : a() 

Che ho capito.

Ma se io uso l'inizializzazione divisa in lista di inizializzazione del costruttore di B, in questo modo:

struct A {}; 

struct B 
{ 
    B() : a{} 
    { 
    } 

    const A& a; 
}; 

Si compila bene.

Quindi la domanda è, perché l'uso di inizializzazione uniforme qui modificare il risultato della compilazione?

Ho provato anche questo con Microsoft Visual C++ 2013. Esso non può essere compilato sia la versione del codice, con lo stesso messaggio di errore:

Error 3 error C2440: 'initializing' : cannot convert from 'int' to 'const A & 

si può avere un gioco rapido con esso qui:

http://ideone.com/7f2t8I

+1

L'inizializzazione uniforme è una funzionalità relativamente nuova e ci si deve aspettare alcuni bug del compilatore. In questo caso, senza doverlo cercare, suppongo che il compilatore Microsoft sia corretto. –

+2

La mia ipotesi: '{}' è interpretato come una chiamata al costruttore predefinito di 'A' (come se si facesse' A a {}; '), quindi viene creato un' A {} 'temporaneo. È quindi legato al const-ref e la sua durata è estesa (come se tu fossi 'const A & a {}', che funziona anche in GCC). Ma non so cosa lo dice lo standard; se è permesso ... Ciò che veramente mi confonde è che MSVC vede un 'int' che non riesco a vedere ... Hai davvero compilato questo codice? – leemes

+0

@JamesKanze Lo capisco, ma non volevo uscire e urlare bug del compilatore. Forse c'è qualcosa sull'inizializzazione uniforme che non conosco e che si comporterebbe diversamente in questa situazione. – Hugo

risposta

6

GCC è corretto nella sua interpretazione di {}. [Dcl.init.list] /p3.8-9 (citando N4296; progetti precedenti ha lo stesso ordine relativo di queste due proiettili):

List-inizializzazione di un oggetto o di riferimento di tipo T è definito come segue:

  • [7 proiettili inapplicabili omessi]

  • Altrimenti, se T è un tipo di riferimento, un prvalue temporaneo del tipo a cui fa riferimento T è copia-list inizializzata o inizializzato per elenco diretto, a seconda del tipo di inizializzazione per il riferimento e il riferimento è associato a tale temporaneo. [Nota : Come di consueto, il legame fallirà e il programma è malformata se il tipo di riferimento è un riferimento Ivalue un tipo non-const. - end note ]

  • In caso contrario, se l'elenco di inizializzazione non contiene elementi, l'oggetto viene inizializzato in base al valore.

List-inizializzare il riferimento colpisce proiettile 3.8, causando la costruzione di una temporanea. Il caso di inizializzazione del valore, in 3.9, non si applica.

valore di inizializzazione di un riferimento è malformata ([dcl.init]/P9):

Un programma che richiede default-inizializzazione o valore di inizializzazione di un'entità di tipo di riferimento è mal formati.


Tuttavia, come di N4296, a [class.base.init]/p8:

Un'espressione temporaneo legato ad un organo di riferimento in un mem-inizializzatore è malato -formed.

Questo è stato aggiunto come risultato di CWG issue 1696, che è un DR (rapporto sui difetti) rispetto a C++ 14.

Pre-CWG1696, lo standard a condizione che (N4140 [class.temporary] /p5.1):

Una temporanea legata a un membro di riferimento in un costruttore di ctor-initializer (12.6. 2) persiste fino all'uscita dal costruttore.

che significa che il riferimento cadrà immediatamente dopo la costruzione. Questa decisione presumibilmente motivata del CWG1696 di non consentire del tutto tali vincoli.

+0

Suppongo che N4296 sia C++ 14. Quindi hanno finalmente corretto qualcosa che è stato un problema (IMHO) dal C++ 98. –

+0

@JamesKanze N4140 è C++ 14. CWG 1696 è un DR contro C++ 14, tuttavia, quindi dovrebbe essere ancora implementato dai compilatori in modalità C++ 14. –

+0

Qualche compilatore ha una modalità C++ 14 pienamente compatibile? (Se è per questo, esiste una modalità C++ 11 pienamente compatibile?) –

Problemi correlati