¿Cómo inicializo una matriz miembro con una initializer_list?

Me estoy poniendo al día con C ++ 0x y estoy probando cosas con g ++ 4.6

Acabo de probar el siguiente código, pensando que funcionaría, pero no comstack. Me sale el error:

incompatible types in assignment of 'std::initializer_list' to 'const int [2]'

 struct Foo { int const data[2]; Foo(std::initializer_list& ini) : data(ini) {} }; Foo f = {1,3}; 

Puede usar un constructor de plantilla variadic en lugar de un constructor de lista de inicializadores:

 struct foo { int x[2]; template  foo(T... ts) : x{ts...} { // note the use of brace-init-list } }; int main() { foo f1(1,2); // OK foo f2{1,2}; // Also OK foo f3(42); // OK; x[1] zero-initialized foo f4(1,2,3); // Error: too many initializers foo f5(3.14); // Error: narrowing conversion not allowed foo f6("foo"); // Error: no conversion from const char* to int } 

EDITAR: si puede vivir sin constness, otra forma sería omitir la inicialización y completar la matriz en el cuerpo de la función:

 struct foo { int x[2]; // or std::array x; foo(std::initializer_list il) { std::copy(il.begin(), il.end(), x); // or std::copy(il.begin(), il.end(), x.begin()); // or x.fill(il.begin()); } } 

De esta manera, sin embargo, pierde los límites de tiempo de comstackción que comprueba que proporciona la solución anterior.

Por lo que puedo decir, el uso de la inicialización de lista del argumento de la función del constructor (8.5.4 / 1) debería ser legal y resuelve muchos de los problemas de los anteriores. Sin embargo, GCC 4.5.1 en ideone.com no puede coincidir con el constructor y lo rechaza.

 #include  struct Foo { std::array< int, 2 > const data; Foo(std::array const& ini) // parameter type specifies size = 2 : data( ini ) {} }; Foo f( {1,3} ); // list-initialize function argument per 8.5.4/1 

Si realmente insistes en initializer_list , puedes usar reinterpret_cast para convertir la matriz subyacente de initializer_list en una matriz estilo C.

 Foo(std::initializer_list ini) // pass without reference- or cv-qualification : data( reinterpret_cast< std::array< int, 2 > const & >( * ini.begin() ) 

Según la discusión aquí :

la syntax correcta para la segunda solución de Potatoswatter es:

 Foo f( {{1,3}} ); //two braces 

un poco feo, no es consistente con el uso común

Solo una pequeña adición a la gran respuesta de JohannesD .

En caso de que no se pasen argumentos al constructor foo , la matriz se inicializará por defecto. Pero a veces desea mantener la matriz subyacente sin inicializar (tal vez por motivos de rendimiento). No puede agregar un constructor predeterminado junto con uno de plantilla variable. La solución temporal es un argumento adicional al constructor de plantilla variable, para distinguirlo del constructor de argumento cero:

 template class array2d { std::array m_Data; public: array2d() {} template  array2d(T t, Types... ts) : m_Data{ { t, ts... } } {} }; 

Entonces, ahora puedes reforzar el objeto o dejarlo sin inicializar:

 array2d arr = { 0, 1, 2, 3 }; // contains 0, 1, 2, 3, 0, 0, 0, ... array2d arr2; // contains garbage 

Actualización 31/07/2016

Han transcurrido tres años rápidamente y los implementadores de comstackdores mejoraron la conformidad estándar de sus productos hasta el nivel en el que el constructor predeterminado ya no se considera ambiguo en presencia del constructor variadic. Por lo tanto, en la práctica, no necesitamos un argumento T t adicional al constructor variadic para eliminar la ambigüedad de los constructores.

Ambos

 array2d() {} 

y

 array2d() = default; 

dejará la matriz sin inicializar si el objeto se está construyendo sin argumentos. Este comportamiento es consistente en todos los comstackdores principales. Ejemplo completo ( rextester ):

 #include  #include  template class array2d { public: std::array m_Data; array2d() = default; template  array2d(Types... ts) : m_Data{ { ts... } } {} }; int main() { array2d arr_init = { 0, 1, 2, 3 }; array2d arr_default; std::cout << "Initialized: \n"; for(const auto& a : arr_init.m_Data) std::cout << a << " "; std::cout << "\n"; std::cout << "Default: \n"; for(const auto& a : arr_default.m_Data) std::cout << a << " "; std::cout << "\n"; } 

Salida:

 Initialized: 0 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Default: 2 0 -519559849 32558 1 32558 0 0 -519634912 32558 -526739248 32558 1 0 2 0 6295032 0 -519531243 32558 0 0 -1716075168 32765 6295648 0 4196192 0 6295648 0 -526527271 32558 1 0 2 0 6295032 0 4196845 0 124 0 0 0 4196768 0 4196518 0 

La eliminación del constructor predeterminado todavía conduce a que se llame al constructor variadic y que el array se inicialice por defecto (con ceros all-in en nuestro caso).

Gracias @Alek por superar este hilo y por llamar la atención sobre estos hechos, y también gracias a todas las personas que trabajan duro en el desarrollo del comstackdor.

No se puede, las matrices no son como otros tipos (y no tienen constructores tomando std :: initializer_list).

Pruebe esto en su lugar:

 struct Foo { const std::vector data; Foo(std::initializer_list ini) : data(ini) {} }; 

Si bien esto no funciona:

 #include  struct Foo { const int data[2]; constexpr Foo(const std::initializer_list& ini): data{ini} {} }; Foo f = {1,3}; 

Encontré que este enfoque simple funciona bien:

 struct Foo { const int data[2]; constexpr Foo(const int a, const int b): data{a,b} {} }; Foo f = {1,3}; 

Por supuesto, el enfoque de plantilla variadic es probablemente mejor si tiene muchos elementos, pero en este caso simple, esto probablemente sea suficiente.

Es decir, si desea definir explícitamente el constructor a partir de las listas de inicializadores. Para la mayoría de los casos POD esto está bien y elegante:

 struct Foo { const int data[2]; }; Foo f = {1,3}; 

Si no le importa la verificación de límites, entonces lo siguiente funcionará.

 struct Foo { int const data[2]; Foo(std::initializer_list ini) : data{*std::begin(ini), *std::next(std::begin(ini), 1)} {} };