Inicializando uma matriz de membro no inicializador de construtor

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

Acredito que o motivo é que os arrays podem ser inicializados apenas com =sintaxe, ou seja:

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

Questões

  1. Como posso fazer o que quero (ou seja, inicializar uma matriz em um construtor (não atribuindo elementos no corpo)). É mesmo possível?
  2. O padrão C ++ 03 diz algo especial sobre a inicialização de agregados (incluindo matrizes) em inicializadores de ctor? Ou a invalidade do código acima é um corolário de algumas outras regras?
  3. As listas de inicializadores C ++ 0x resolvem o problema?

PS Por favor, não mencione vetores, boost :: arrays, e sua superioridade em relação a arrays, que eu conheço bem.

Armen Tsirunyan
fonte
Você também está ciente da existência de matrizes de tamanho fixo de impulso, que fornecem construtores?
Benoît,
2
@ Benoît: Eu sou. Mas eu preciso saber sobre matrizes simples :)
Armen Tsirunyan

Respostas:

55
  1. Como posso fazer o que quero (ou seja, inicializar uma matriz em um construtor (não atribuindo elementos no corpo)). É mesmo possível?

Sim. Ele está usando uma estrutura que contém uma matriz. Você diz que já sabe disso, mas eu não entendo a pergunta. Dessa forma, você fazer inicializar uma matriz no construtor, sem atribuições no corpo. Isso é o que boost::arrayfaz.

O padrão C ++ 03 diz algo especial sobre a inicialização de agregados (incluindo matrizes) em inicializadores de ctor? Ou a invalidade do código acima é um corolário de algumas outras regras?

Um inicializador de mem usa inicialização direta. E as regras da cláusula 8 proíbem esse tipo de coisa. Não tenho certeza sobre o seguinte caso, mas alguns compiladores permitem isso.

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

Consulte este GCC PR para obter mais detalhes.

As listas de inicializadores C ++ 0x resolvem o problema?

Sim, eles fazem. No entanto, sua sintaxe é inválida, eu acho. Você tem que usar chaves diretamente para disparar a inicialização da lista

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
fonte
Eu tropecei nisso quando escrevi: char * const foo[6];membro da classe. Ele requer o inicializador para compilar em C ++ 11.
JATothrim
33

C ++ 98 não fornece uma sintaxe direta para nada além de zerar (ou para elementos não POD, inicialização de valor) o array. Para isso, basta escrever C(): arr() {}.

Acho que Roger Pate está errado sobre as supostas limitações da inicialização do agregado C ++ 0x, mas estou com preguiça de pesquisar ou verificar, e isso não importa, não é? EDIT : Roger estava falando sobre "C ++ 03", eu interpretei incorretamente como "C ++ 0x". Desculpe, Roger. ☺

Uma solução alternativa do C ++ 98 para o código atual é envolver a matriz em a structe inicializá-la a partir de uma constante estática desse tipo. Os dados devem residir em algum lugar de qualquer maneira. De cara, pode ter a seguinte aparência:

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}};
Saúde e hth. - Alf
fonte
Que limitações eu disse que 0x tem?
@Roger: "inicialização agrregate ... não cabe no inicializador ctor". Apenas verificar C ++ 0x draft N3126, a sintaxe de um inicializador de mem , em §12.5.2 / 1, inclui o uso de uma lista de inicialização com chaves .
Saúde e hth. - Alf
6
As duas primeiras palavras da minha frase são em C ++ 03, ...
8

Gambiarra:

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
fonte
3
  1. Infelizmente não.
  2. Você simplesmente não pode da maneira que deseja, pois não é permitido pela gramática (mais abaixo). Você só pode usar a inicialização tipo ctor e, como você sabe, isso não está disponível para inicializar cada item em matrizes.
  3. Acredito que sim, pois eles generalizam a inicialização em toda a linha de muitas maneiras úteis. Mas não tenho certeza dos detalhes.

Em C ++ 03, a inicialização agregada só se aplica com sintaxe semelhante à abaixo, que deve ser uma instrução separada e não se encaixa em um inicializador de ctor.

T var = {...};

fonte
2

E se

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

?

Compila bem no g ++ 4.8

eold
fonte
Este é um padrão? Você pode citar a cláusula relevante, por favor?
Armen Tsirunyan
2
Não compila no Visual C ++.
sergiol
-2

Você deseja iniciar um array de ints em seu construtor? Aponte para uma matriz estática.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
fonte
2
Esta é uma má ideia, porque se você alterar essa matriz, ela será alterada para todas as instâncias dessa classe.
morty