c++ - examples - initialize array labview
¿Cómo inicializo una matriz miembro con una initializer_list? (7)
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 compila. Me sale el error:
incompatible types in assignment of ''std::initializer_list<const int>'' to ''const int [2]''
struct Foo
{
int const data[2];
Foo(std::initializer_list<int const>& ini)
: data(ini)
{}
};
Foo f = {1,3};
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<int> data;
Foo(std::initializer_list<int> ini) : data(ini)
{}
};
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 <array>
struct Foo
{
std::array< int, 2 > const data;
Foo(std::array<int, 2> 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<int> ini) // pass without reference- or cv-qualification
: data( reinterpret_cast< std::array< int, 2 > const & >( * ini.begin() )
Puede usar un constructor de plantilla variadic en lugar de un constructor de lista de inicializadores:
struct foo {
int x[2];
template <typename... T>
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<int, 2> x;
foo(std::initializer_list<int> 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 compilación que comprueba que proporciona la solución anterior.
Según la discusión here :
la sintaxis 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
Si bien esto no funciona:
#include <initializer_list>
struct Foo
{
const int data[2];
constexpr Foo(const std::initializer_list<int>& 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<int> ini)
: data{*std::begin(ini), *std::next(std::begin(ini), 1)} {}
};
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 T, size_t rows, size_t cols>
class array2d
{
std::array<T, rows * cols> m_Data;
public:
array2d() {}
template <typename T, typename... Types>
array2d(T t, Types... ts) : m_Data{ { t, ts... } } {}
};
Entonces, ahora puedes reforzar el objeto o dejarlo sin inicializar:
array2d<int, 6, 8> arr = { 0, 1, 2, 3 }; // contains 0, 1, 2, 3, 0, 0, 0, ...
array2d<int, 6, 8> arr2; // contains garbage
Actualización 31/07/2016
Han transcurrido tres años rápidamente y los implementadores de compiladores 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 compiladores principales. Ejemplo completo ( rextester ):
#include <array>
#include <iostream>
template<class T, size_t rows, size_t cols>
class array2d
{
public:
std::array<T, rows * cols> m_Data;
array2d() = default;
template <typename... Types>
array2d(Types... ts) : m_Data{ { ts... } } {}
};
int main()
{
array2d<int, 6, 8> arr_init = { 0, 1, 2, 3 };
array2d<int, 6, 8> 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 compilador.