2014-10-03 26 views
7

Questa C++ 11 codice funziona bene per me:Differenza tra std :: vector e std :: array di inizializzazione elenca

#include <iostream> 
#include <vector> 
#include <array> 
using namespace std; 

struct str { 
    int first, last; 
}; 


vector<str> fields { 
    {1,2}, {3,4}, {5,6} 
}; 

int main() 
{ 
    for (str s : fields) 
     cout << s.first << " " << s.last << endl; 
} 

esso stampa i sei valori attesi.

Ma se cambio vector<str> a array<str,3>, gcc mi dà questo errore: "troppi inizializzatori per 'std :: array'".

Se cambio l'inizializzazione di fields così:

array<str,3> fields { 
    str{1,2}, str{3,4}, str{5,6} 
}; 

Le cose funzionano bene.

Allora, perché ho bisogno str{1,2} quando si utilizza std::array, ma solo quando si utilizza {1,2}std::vector?

risposta

6

Sede di cppreference su aggregate initialization.

The effects of aggregate initialization are:

  • Each array element or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.

  • If the initializer clause is a nested braced-init-list, the corresponding class member is itself an aggregate: aggregate initialization is recursive.

Questo significa che se si ha un aggregato all'interno della vostra struct, come ad esempio:

struct str { 
    struct asdf 
    { 
     int first, last; 
    } asdf; 
}; 

asdf sarebbe inizializzato dal primo nidificato brace-init-list, cioè { { 1, 2 } }. Il motivo per cui in genere sono necessarie due coppie di parentesi è perché l'elenco nidificato di brace-init inizializza l'aggregato sottostante in std::array (ad esempio,).

Tuttavia, è ancora possibile inizializzare l'array come questo:

array<str,3> fields { 
    1, 2, 3, 4, 5, 6 
}; 

o:

array<str,3> fields { { 
    1, 2, 3, 4, 5, 6 
} }; 

invece.

D'altra parte, la modalità di inizializzazione del vettore è coperta da list initialization. std::vector ha un costruttore che accetta uno std::initializer_list.

The effects of list initialization of an object of type T are:

  • Otherwise, the constructors of T are considered, in two phases:

    • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

Nota che non sarebbe in grado di inizializzare il vettore (come questo:

vector<str> fields { 
    1,2, 3,4, 5,6 
}; 

ma:.

vector<int> fields { 
    1,2, 3,4, 5,6 
}; 

è perfettamente bene

4

È perché l'inizializzazione dell'array è costruita un po 'diversa dal vettore.
Per inizializzare un array è necessario utilizzare due parentesi.
A causa di una funzione di sintassi, è possibile ignorarlo se si inizializza un solo oggetto.
Così il seguente è ok:

array{1,2,3} -> array{{1,2,3}} 

Ma nel tuo esempio si inizializza più oggetti in modo che il compilatore non aggiunge parentesi graffe aggiuntive. L'uso di due parentesi risolve questo. sezione

array<str,3> fields {{ 
    {1,2}, {3,4}, {5,6} 
}}; 
Problemi correlati