Inicjowanie tablicy składowej w inicjatorze konstruktora

99
class C 
{
public:
 C() : arr({1,2,3}) //doesn't compile
{}
    /*
    C() : arr{1,2,3} //doesn't compile either
{}
    */
private:
 int arr[3];
};

Uważam, że powodem jest to, że tablice można zainicjować tylko za pomocą =składni, czyli:

int arr[3] = {1,3,4};

pytania

  1. Jak mogę zrobić to, co chcę zrobić (to znaczy zainicjować tablicę w konstruktorze (bez przypisywania elementów w treści)). Czy to w ogóle możliwe?
  2. Czy standard C ++ 03 mówi coś specjalnego na temat inicjowania agregatów (w tym tablic) w inicjalizatorach ctor? Czy nieważność powyższego kodu jest następstwem innych reguł?
  3. Czy listy inicjalizujące C ++ 0x rozwiązują problem?

PS Proszę nie wspominać o wektorach, boost :: tablice i ich wyższości nad tablicami, o czym dobrze wiem.

Armen Tsirunyan
źródło
Czy zdajesz sobie również sprawę z istnienia tablic o stałym rozmiarze boost, które zapewniają konstruktory?
Benoît
2
@ Benoît: Jestem. Ale muszę wiedzieć o zwykłych tablicach :)
Armen Tsirunyan

Odpowiedzi:

56
  1. Jak mogę zrobić to, co chcę zrobić (to znaczy zainicjować tablicę w konstruktorze (bez przypisywania elementów w treści)). Czy to w ogóle możliwe?

Tak. Używa struktury, która zawiera tablicę. Mówisz, że już o tym wiesz, ale wtedy nie rozumiem pytania. W ten sposób możesz zrobić zainicjować tablicy w konstruktorze, bez zadań w organizmie. To właśnie boost::arrayrobi.

Czy standard C ++ 03 mówi coś specjalnego na temat inicjowania agregatów (w tym tablic) w inicjalizatorach ctor? A może nieważność powyższego kodu jest następstwem innych reguł?

Mem-initializer używa bezpośredniej inicjalizacji. A zasady klauzuli 8 zabraniają takich rzeczy. Nie jestem pewien co do następującego przypadku, ale niektóre kompilatory na to pozwalają.

struct A {
  char foo[6];
  A():foo("hello") { } /* valid? */
};

Więcej informacji można znaleźć w dokumencie GCC PR .

Czy listy inicjalizujące C ++ 0x rozwiązują problem?

Tak, robią. Myślę jednak, że twoja składnia jest nieprawidłowa. Musisz użyć bezpośrednio nawiasów klamrowych, aby uruchomić inicjalizację listy

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
źródło
Natknąłem się na to, kiedy napisałem: char * const foo[6];członek klasy. To wymaga inicjatora do kompilacji w C ++ 11.
JATothrim,
33

C ++ 98 nie dostarcza bezpośredniej składni dla niczego poza zerowaniem (lub dla elementów innych niż POD, inicjalizacją wartości) tablicy. Po prostu piszesz C(): arr() {}.

Wydaje mi się, że Roger Pate myli się co do rzekomych ograniczeń inicjalizacji agregacji C ++ 0x, ale jestem zbyt leniwy, żeby to sprawdzić lub sprawdzić, i to nie ma znaczenia, prawda? EDYCJA : Roger mówił o „C ++ 03”, źle go odczytałem jako „C ++ 0x”. Przepraszam, Roger. ☺

Obejściem C ++ 98 dla bieżącego kodu jest zawinięcie tablicy w a structi zainicjowanie jej ze stałej statycznej tego typu. Dane i tak muszą gdzieś znajdować się. Bez mankietu może to wyglądać tak:

class C 
{
public:
    C() : arr( arrData ) {}

private:
     struct Arr{ int elem[3]; };
     Arr arr;
     static Arr const arrData;
};

C::Arr const C::arrData = {{1, 2, 3}};
Pozdrawiam i hth. - Alf
źródło
Jakie ograniczenia powiedziałem 0x?
@Roger: "inicjalizacja zbiorcza ... nie pasuje do inicjalizatora ctor". Wystarczy sprawdzić wersję roboczą C ++ 0x N3126, składnia inicjalizatora pamięci , w §12.5.2 / 1, obejmuje użycie listy init-init .
Pozdrawiam i hth. - Alf
6
Pierwsze dwa słowa mojego zdania to In C ++ 03, ...
8

Obejście:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x
   T arr[N];
};


class C : private simple_array<int, 3> 
{
      static simple_array<int, 3> myarr() {
           simple_array<int, 3> arr = {1,2,3};
           return arr;
      }
public:
      C() : simple_array<int, 3>(myarr()) {}
};
Alexey Malistov
źródło
3
  1. Niestety nie.
  2. Po prostu nie możesz tak, jak chcesz, ponieważ gramatyka nie pozwala na to (więcej poniżej). Możesz użyć tylko inicjalizacji podobnej do ctora i, jak wiesz, nie jest dostępna do inicjowania każdego elementu w tablicach.
  3. Uważam, że tak, ponieważ uogólniają inicjalizację na wiele użytecznych sposobów. Ale nie jestem pewien szczegółów.

W C ++ 03 inicjalizacja agregacji ma zastosowanie tylko ze składnią podobną do poniższej, która musi być oddzielną instrukcją i nie pasuje do inicjatora ctor.

T var = {...};

źródło
2

Co powiesz na

...
  C() : arr{ {1,2,3} }
{}
...

?

Kompiluje się dobrze na g ++ 4.8

eold
źródło
Czy to standard? Czy może Pan zacytować odpowiednią klauzulę?
Armen Tsirunyan
2
Nie kompiluje się w języku Visual C ++.
sergiol
-3

Chcesz zainicjować tablicę int w swoim konstruktorze? Skieruj go na tablicę statyczną.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
źródło
2
To zły pomysł, ponieważ jeśli zmienisz tę tablicę, zostanie ona zmieniona dla wszystkich instancji tej klasy.
morty