41

Supponiamo che sia inizializzato un std::array. Va bene se si utilizza parentesi graffe doppie:Brace elision nell'inizializzazione std :: array

std::array<int, 2> x = {{0, 1}}; 
std::array<int, 2> x{{0, 1}}; 

E 'anche bene usare singole parentesi nella buona di inizializzazione aggregata vecchio, come l'elisione tutore si prenderà cura delle parentesi graffe mancanti:

std::array<int, 2> x = {0, 1}; 

tuttavia, è va bene usare l'inizializzazione della lista con parentesi singole? GCC lo accetta, Clang lo rifiuta con "non può omettere le parentesi attorno all'inizializzazione di subobject quando si utilizza l'inizializzazione dell'elenco diretto".

std::array<int, 2> x{0, 1}; 

L'unica parte dello standard in cui è menzionato tutore elisione è 8.5.1/12, che dice:

Tutti tipo implicito conversioni (clausola 4) sono considerati durante l'inizializzazione del membro aggregato con un'espressione-assegnazione. Se l'espressione-assegnazione può inizializzare un membro, il membro viene inizializzato. Altrimenti, se il membro è esso stesso un sottogruppo, si assume l'elisione di parentesi e si considera l'espressione di assegnazione per l'inizializzazione del primo membro del sottoaggregato.

8.5.1 riguarda specificamente l'inizializzazione di aggregazione, quindi ciò significa che Clang è corretto da rifiutare, giusto? Non così in fretta. 8.5.4/3 dice:

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

[...]

- Altrimenti, se T è un aggregato, aggregato l'inizializzazione viene eseguita (8.5.1).

ho pensa vuol dire che l'esatto stesse regole con l'inizializzazione di aggregazione, tra cui brace elisione, si applicano, cioè GCC è corretto accettare.

Ammetto che la formulazione non è particolarmente chiara. Quindi, quale compilatore ha ragione nel trattare il terzo frammento? L'elisione della coppia si verifica in fase di inizializzazione della lista o no?

+0

Nizza domanda! Potrebbe valere la pena menzionare quale standard stai usando. Lo standard C++ 11 o, in caso contrario, quale particolare progetto. – juanchopanza

+0

"inizializzazione tipo assegnazione" è chiamato inizializzazione della copia. Chiama il costruttore di copie, non l'operatore di assegnazione. – TemplateRex

+0

@TemplateRex: è per questo che ho usato il lavoro "mi piace". – Fanael

risposta

20

Si applica l'elisione del tutore, ma non in C++ 11. In C++ 14, si applicano a causa di http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270. Se sei fortunato, Clang lo sosterrà nella loro modalità C++ 11 (speriamo che lo faranno!).

+0

A partire da ora, 'clang-5.0' in archlinux non supporta ancora elision brace anche con' -std = C++ 17'. –

3

Rilevante: http://en.cppreference.com/w/cpp/language/aggregate_initialization

Insomma,

struct S { 
    int x; 
    struct Foo { 
     int i; 
     int j; 
     int a[3]; 
    } b; 
}; 
S s1 = { 1, { 2, 3, {4, 5, 6} } }; 
S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision 
S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax 
S s4{1, 2, 3, 4, 5, 6}; // error in C++11: brace-elision only allowed with equals sign 
         // okay in C++14