C ++: inizializzatore costruttore per array

Sto avendo un crampo al cervello … come faccio a inizializzare correttamente una matrice di oggetti in C ++?

esempio non-array:

struct Foo { Foo(int x) { /* ... */ } }; struct Bar { Foo foo; Bar() : foo(4) {} }; 

esempio di array:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; // ??? I know the following syntax is wrong, but what's correct? Baz() : foo[0](4), foo[1](5), foo[2](6) {} }; 

modifica: le idee di soluzione pazzesche e selvagge sono apprezzate, ma non mi aiuteranno nel mio caso. Sto lavorando su un processore embedded dove std :: vector e altri costrutti STL non sono disponibili e la soluzione ovvia è quella di creare un costruttore predefinito e di avere un metodo init() esplicito che può essere chiamato dopo il tempo di costruzione, in modo che Non devo assolutamente usare gli inizializzatori. (Questo è uno di quei casi in cui sono stato rovinato dall’ultima parola chiave di Java + flessibilità con i costruttori.)

Non c’è alcun modo. È necessario un costruttore predefinito per i membri dell’array e verrà chiamato, in seguito, è ansible eseguire qualsiasi inizializzazione desiderata nel costruttore.

Solo per aggiornare questa domanda per C ++ 11, questo è ora ansible e molto naturale:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo{{4}, {5}, {6}} { } }; 

Queste parentesi possono anche essere elise per una ancora più concisa:

 struct Baz { Foo foo[3]; Baz() : foo{4, 5, 6} { } }; 

Che può essere facilmente esteso anche agli array multidimensionali:

 struct Baz { Foo foo[3][2]; Baz() : foo{1, 2, 3, 4, 5, 6} { } }; 

Al momento, non è ansible utilizzare l’elenco di inizializzazione per i membri dell’array. Sei bloccato a farlo nel modo più duro.

 class Baz { Foo foo[3]; Baz() { foo[0] = Foo(4); foo[1] = Foo(5); foo[2] = Foo(6); } }; 

In C ++ 0x puoi scrivere:

 class Baz { Foo foo[3]; Baz() : foo({4, 5, 6}) {} }; 

Sfortunatamente non c’è modo di inizializzare i membri dell’array fino a C ++ 0x.

Potresti usare std :: vector e push_back le istanze di Foo nel corpo del costruttore.

Puoi dare a Foo un costruttore predefinito (potrebbe essere privato e rendere Baz un amico).

È ansible utilizzare un object array che è ansible copiare (boost o std :: tr1) e inizializzarsi da un array statico:

 #include  struct Baz { boost::array foo; static boost::array initFoo; Baz() : foo(initFoo) { } }; boost::array Baz::initFoo = { 4, 5, 6 }; 

È ansible utilizzare auto parola chiave auto C ++ 0x insieme alla specializzazione del modello , ad esempio una funzione chiamata boost::make_array() (simile a make_pair() ). Nel caso in cui N sia 1 o 2 argomenti, possiamo quindi scrivere la variante A come

 namespace boost { /*! Construct Array from @p a. */ template  boost::array make_array(const T & a) { return boost::array ({{ a }}); } /*! Construct Array from @pa, @p b. */ template  boost::array make_array(const T & a, const T & b) { return boost::array ({{ a, b }}); } } 

e variante B come

 namespace boost { /*! Construct Array from @p a. */ template  boost::array make_array(const T & a) { boost::array x; x[0] = a; return x; } /*! Construct Array from @pa, @p b. */ template  boost::array make_array(const T & a, const T & b) { boost::array x; x[0] = a; x[1] = b; return x; } } 

GCC-4.6 con -std=gnu++0x e -O3 genera lo stesso identico codice binario per

 auto x = boost::make_array(1,2); 

usando sia A che B come fa per

 boost::array x = {{1,2}}; 

Per i tipi definiti dall’utente (UDT), tuttavia, la variante B risulta in un costruttore di copie extra , che di solito rallenta le cose e dovrebbe quindi essere evitato.

Notare boost::make_array errori boost::make_array quando lo si chiama con letterali espliciti di char array come nel caso seguente

 auto x = boost::make_array("a","b"); 

Credo che questa sia una cosa positiva dato che i letterali const char* possono essere ingannevoli nel loro uso.

I modelli Variadic , disponibili in GCC dal 4.5, possono essere ulteriormente utilizzati per ridurre il codice della piastra caldaia di specializzazione modello per ogni N in una definizione di modello singolo di boost::make_array() definito come

 /*! Construct Array from @pa, @p b. */ template  boost::array make_array(T a, const R & ... b) { return boost::array({{ a, b... }}); } 

Funziona praticamente come ci aspettiamo. Il primo argomento determina l’argomento del modello di boost::array T e tutti gli altri argomenti vengono convertiti in T Per alcuni casi questo potrebbe non essere desiderabile, ma non sono sicuro di come sia ansible specificare l’uso di modelli variadici.

Forse boost::make_array() dovrebbe andare nelle librerie Boost?

Questo sembra funzionare, ma non sono convinto che sia giusto:

 #include  struct Foo { int x; Foo(int x): x(x) { } }; struct Baz { Foo foo[3]; static int bar[3]; // Hmm... Baz() : foo(bar) {} }; int Baz::bar[3] = {4, 5, 6}; int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

Produzione:

 $ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit g++ -pedantic arrayinit.cpp -o arrayinit 5 

Caveat emptor.

Edit: no, Comeau lo rifiuta.

Un'altra modifica: è una specie di imbroglio, semplicemente spinge l'inizializzazione dell'array membro per membro in un posto diverso. Quindi richiede ancora a Foo di avere un costruttore predefinito, ma se non hai std::vector allora puoi implementare per te il minimo indispensabile di cui hai bisogno:

 #include  struct Foo { int x; Foo(int x): x(x) { }; Foo(){} }; // very stripped-down replacement for vector struct Three { Foo data[3]; Three(int d0, int d1, int d2) { data[0] = d0; data[1] = d1; data[2] = d2; } Foo &operator[](int idx) { return data[idx]; } const Foo &operator[](int idx) const { return data[idx]; } }; struct Baz { Three foo; static Three bar; // construct foo using the copy ctor of Three with bar as parameter. Baz() : foo(bar) {} // or get rid of "bar" entirely and do this Baz(bool) : foo(4,5,6) {} }; Three Baz::bar(4,5,6); int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

z.foo non è in realtà un array, ma sembra più simile a un vettore. L'aggiunta delle funzioni begin() e end() a Three è banale.

Solo il costruttore predefinito può essere chiamato quando si creano oggetti in un array.

Nel caso specifico in cui l’array è un membro dati della class non è ansible inizializzarlo nella versione corrente della lingua. Non c’è syntax per questo. Fornire un costruttore predefinito per gli elementi dell’array o usare std::vector .

Un array standalone può essere inizializzato con l’inizializzatore aggregato

 Foo foo[3] = { 4, 5, 6 }; 

ma sfortunatamente non esiste una syntax corrispondente per l’elenco di inizializzazione del costruttore.

Non esiste una syntax per la costruzione di array che possa essere utilizzata in questo contesto, almeno non direttamente. Puoi realizzare ciò che stai cercando di ottenere con qualcosa del tipo:

 Bar::Bar() { static const int inits [] = {4,5,6}; static const size_t numInits = sizeof(inits)/sizeof(inits[0]); std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo } 

… ma dovrai fornire a Foo un costruttore predefinito.

Idee da una mente contorta:

 class mytwistedclass{ static std::vector initVector; mytwistedclass() { //initialise with initVector[0] and then delete it :-) } }; 

ora imposta questo initVector su qualcosa che vuoi prima di istanziare un object. Quindi i tuoi oggetti sono inizializzati con i tuoi parametri.

Puoi farlo, ma non è carino:

 #include  class A { int mvalue; public: A(int value) : mvalue(value) {} int value() { return mvalue; } }; class B { // TODO: hack that respects alignment of A.. maybe C++14's alignof? char _hack[sizeof(A[3])]; A* marr; public: B() : marr(reinterpret_cast(_hack)) { new (&marr[0]) A(5); new (&marr[1]) A(6); new (&marr[2]) A(7); } A* arr() { return marr; } }; int main(int argc, char** argv) { B b; A* arr = b.arr(); std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n"; return 0; } 

Se inserisci questo nel tuo codice, spero che tu abbia una buona ragione.

Questa è la mia soluzione per il tuo riferimento:

 struct Foo { Foo(){}//used to make compiler happy! Foo(int x){/*...*/} }; struct Bar { Foo foo[3]; Bar() { //initialize foo array here: for(int i=0;i<3;++i) { foo[i]=Foo(4+i); } } }; 

in Visual Studio 2012 o superiore, puoi fare così

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo() { } }; 
 class C { static const int myARRAY[10]; // only declaration !!! public: C(){} } const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition int main(void) { C myObj; }