2014-10-03 21 views
7

ten C++ 11 kod działa dobrze dla mnie:Różnica między std :: vector i std :: array inicjatora wymienia

#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; 
} 

Drukuje sześć Spodziewane wartości.

Ale jeśli zmienię vector<str> na array<str,3>, gcc daje mi ten błąd: "zbyt wiele inicjalizatorów dla" std :: array "".

Jeśli zmienię inicjalizacji fields tak:

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

wszystko działa dobrze.

Więc dlaczego muszę str{1,2} podczas korzystania std::array, ale tylko {1,2} podczas korzystania std::vector?

Odpowiedz

6

Zobacz sekcję cppreference na stronie 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.

Oznacza to, że jeśli miał agregat wewnątrz swojej struktury, takie jak:

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

asdf zostanie zainicjowana przez pierwszy zagnieżdżonego Brace-init-listy, tj { { 1, 2 } }. Powodem, dla którego zazwyczaj potrzebne są dwie pary nawiasów klamrowych, jest to, że zagnieżdżona lista inicjująca brace inicjuje agregat bazowy w std::array (na przykład T a[N]).

Jednak nadal można zainicjować tablicę tak:

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

czyli

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

zamiast.

Z drugiej strony sposób inicjowania wektora jest objęty list initialization. std::vector ma konstruktora, który akceptuje 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

pamiętać, że nie będzie w stanie zainicjować wektora (tak:

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

ale.

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

jest perfekcyjnie

4

Dzieje się tak, ponieważ inicjalizacja macierzy została zbudowana nieco inaczej niż wektor.
Aby zainicjować tablicę, należy użyć dwóch nawiasów klamrowych.
Z powodu funkcji składni można ją pominąć, jeśli zainicjujesz tylko jeden obiekt.
Więc po to ok:

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

Ale w swojej przykład zainicjować wiele obiektów więc kompilator nie dodaje dodatkowe szelki. Użycie dwóch aparatów ortodontycznych to rozwiązuje.

array<str,3> fields {{ 
    {1,2}, {3,4}, {5,6} 
}}; 
Powiązane problemy