Initialisation d'un tableau de membres dans l'initialiseur du constructeur

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

Je pense que la raison en est que les tableaux ne peuvent être initialisés qu'avec la =syntaxe, c'est-à-dire:

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

Des questions

  1. Comment puis-je faire ce que je veux faire (c'est-à-dire initialiser un tableau dans un constructeur (sans affecter des éléments dans le corps)). Est-ce même possible?
  2. La norme C ++ 03 dit-elle quelque chose de spécial sur l'initialisation des agrégats (y compris les tableaux) dans les initialiseurs ctor? Ou l'invalidité du code ci-dessus est un corollaire de certaines autres règles?
  3. Les listes d'initialiseurs C ++ 0x résolvent-elles le problème?

PS Veuillez ne pas mentionner les vecteurs, boost :: arrays et leur supériorité par rapport aux tableaux, dont je suis bien conscient.

Armen Tsirunyan
la source
Connaissez-vous également l'existence de tableaux boost de taille fixe, qui fournissent des constructeurs?
Benoît
2
@ Benoît: je le suis. Mais j'ai besoin de savoir sur les tableaux simples :)
Armen Tsirunyan

Réponses:

56
  1. Comment puis-je faire ce que je veux faire (c'est-à-dire initialiser un tableau dans un constructeur (sans affecter des éléments dans le corps)). Est-ce même possible?

Oui. Il utilise une structure qui contient un tableau. Vous dites que vous le savez déjà, mais je ne comprends pas la question. De cette façon, vous faites initialiser un tableau dans le constructeur, sans affectations dans le corps. C'est ce que boost::arrayfait.

La norme C ++ 03 dit-elle quelque chose de spécial sur l'initialisation des agrégats (y compris les tableaux) dans les initialiseurs ctor? Ou l'invalidité du code ci-dessus est un corollaire de certaines autres règles?

Un mem-initializer utilise l'initialisation directe. Et les règles de l'article 8 interdisent ce genre de chose. Je ne suis pas vraiment sûr du cas suivant, mais certains compilateurs le permettent.

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

Voir ce PR GCC pour plus de détails.

Les listes d'initialiseurs C ++ 0x résolvent-elles le problème?

Oui, ils le font. Cependant, votre syntaxe est invalide, je pense. Vous devez utiliser des accolades directement pour déclencher l'initialisation de la liste

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
la source
Je suis tombé dessus quand j'ai écrit: char * const foo[6];membre de la classe. Il nécessite que l'initialiseur compile en C ++ 11.
JATothrim
33

C ++ 98 ne fournit pas de syntaxe directe pour autre chose que la mise à zéro (ou pour les éléments non POD, l'initialisation de la valeur) du tableau. Pour cela, vous écrivez simplement C(): arr() {}.

Je pense que Roger Pate se trompe sur les prétendues limitations de l'initialisation d'agrégat C ++ 0x, mais je suis trop paresseux pour le rechercher ou le vérifier, et cela n'a pas d'importance, n'est-ce pas? EDIT : Roger parlait de "C ++ 03", je l'ai mal interprété comme "C ++ 0x". Désolé, Roger. ☺

Une solution de contournement C ++ 98 pour votre code actuel consiste à encapsuler le tableau dans un structet à l'initialiser à partir d'une constante statique de ce type. Les données doivent de toute façon résider quelque part. De la manchette, cela peut ressembler à ceci:

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}};
Bravo et hth. - Alf
la source
Quelles limites ai-je dit que 0x a?
@Roger: "l'initialisation agrégée ... ne rentre pas dans un initialiseur ctor". En vérifiant simplement le brouillon N3126 de C ++ 0x, la syntaxe d'un initialiseur de mémoire, au §12.5.2 / 1, inclut l'utilisation d'une liste d' initialisation entre accolades .
Acclamations et hth. - Alf
6
Les deux premiers mots de ma phrase sont en C ++ 03, ...
8

Solution de contournement:

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
la source
3
  1. Non malheureusement.
  2. Vous ne pouvez tout simplement pas comme vous le souhaitez, car ce n'est pas autorisé par la grammaire (plus ci-dessous). Vous ne pouvez utiliser qu'une initialisation de type ctor et, comme vous le savez, elle n'est pas disponible pour l'initialisation de chaque élément dans les tableaux.
  3. Je pense que oui, car ils généralisent l'initialisation à tous les niveaux de nombreuses manières utiles. Mais je ne suis pas sûr des détails.

En C ++ 03, l'initialisation d'agrégat s'applique uniquement avec une syntaxe similaire à celle ci-dessous, qui doit être une instruction distincte et ne rentre pas dans un initialiseur ctor.

T var = {...};

la source
2

Que diriez-vous

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

?

Compile bien sur g ++ 4.8

vieux
la source
Est-ce la norme? Pouvez-vous citer la clause pertinente, s'il vous plaît?
Armen Tsirunyan
2
Ne compile pas sur Visual C ++.
sergiol
-3

Vous voulez initier un tableau d'entiers dans votre constructeur? Faites-le pointer vers un tableau statique.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
la source
2
C'est une mauvaise idée, car si vous modifiez ce tableau, il est modifié pour toutes les instances de cette classe.
morty