valor una secuencias secuencia numeros number modificar last generar ejemplos crear asignar actualizar c++ constructor compile-time

c++ - secuencias - ¿Cómo inicializar una secuencia de objetos no movibles, no copiables?



secuencias sql ejemplos (3)

Digamos que tengo un tipo que no es ni movible ni se puede copiar:

struct foo { explicit foo( size_t ){} ~foo(){} foo( foo const & ) = delete; foo( foo && ) = delete; foo& operator=( foo const & ) = delete; foo& operator=( foo & ) = delete; };

Ahora, dado un número conocido en tiempo de compilación (llámalo N), ¿hay alguna manera de que pueda crear una "secuencia" de estos en la pila con cada uno inicializado con los números 0 a N-1? Me sentiría satisfecho con una matriz de estilo C foo[N] , una std::array< foo, N > , o incluso una std::tuple de algún tipo.

Lo que intento evitar es escribir:

foo f0( 0 ), f1( 1 ), ... fNminus1( N-1 );

cuando parece que esto es algo que el compilador debería poder hacer por mí. Lo mejor que he podido encontrar es usar boost::optional .

boost::optional< foo > f[N]; for( size_t i = 0U; i < N; ++i ) f[i] = boost::in_place( i );

Pero eso depende de la lógica de tiempo de ejecución aunque toda la información requerida está disponible en tiempo de compilación. Además, me queda algo que se comporta como una serie de indicadores.


Aunque no es estrictamente una matriz, puede lograrlo con la recursión de la plantilla

template< typename T, size_t N > struct type_array : public type_array< T, N-1 > { // this is the Nth element T elem; // it is constructed with N type_array() : elem( N ) {} // member function to return the Nth element T & get( size_t n ) { if ( n == N ) { return elem; } else { return type_array< T, N-1 >::get( n ); } } }; // base case when N == 0 template< typename T > struct type_array<T, 0> { T elem; type_array() : elem( 0 ) {} T & get( size_t n ) { return elem; } };

Uso:

type_array< foo, 100 > foo_array; // construct 100 foos foo_array.get(1); // foo with n == 1 foo_array.get(2); // foo with n == 2


// create a type with the proper alignment typedef std::aligned_storage<sizeof(foo), std::alignment_of<foo>::value>::type buffer_type; const int N = 10; // create an array of uninitialized raw data buffer_type storage_buffer[N]; // initialize each foo object with placement new for (size_t i=0; i<N; ++i) new (storage_buffer + i) foo(i); foo * fp = (foo*)(&storage_buffer); // access your foo objects via fp // you must manually call the destructor of each object for (size_t i=0; i<N; ++i) fp[i].~foo();

Si eso parece una gran molestia, lo es. Pero podrías encapsular fácilmente esa funcionalidad en una clase.


Como la respuesta de Benjamin Lindley, pero lleno en una clase:

#include <type_traits> #include <utility> #include <new> template<typename T> class uninitialized { public: constexpr uninitialized() { } ~uninitialized() { get().~T(); } explicit uninitialized(const uninitialized& other) { construct(other); } explicit uninitialized(uninitialized&& other) { construct(std::move(other)); } template<class... Args> explicit uninitialized(Args&&... args) { construct(std::forward<Args>(args)...); } template<class... Args> void construct(Args&&... args) noexcept { static_assert(std::is_nothrow_constructible<T, Args...>::value, "constructor should not throw!"); ::new(getPointer()) T (std::forward<Args>(args)...); } uninitialized& operator = (const T& t) { get() = t; return *this; } uninitialized& operator = (T&& t) { get() = std::move(t); return *this; } T* operator -> () { return getPointer(); } T& operator * () { return get(); } T* operator & () { return getPointer(); } T* getPointer() { return reinterpret_cast<T*>(&data); } T& get() { return *reinterpret_cast<T*>(&data); } const T* operator -> () const { return getPointer(); } const T& operator * () const { return get(); } const T* operator & () const { return getPointer(); } const T* getPointer() const { return reinterpret_cast<const T*>(&data); } const T& get() const { return *reinterpret_cast<const T*>(&data); } private: std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type data; };

Ahora las cosas son un poco más fáciles:

uninitialized<foo> f[N]; for (size_t i = 0; i < N; ++i) f[i].construct(i); for (const auto& fooref : f) fooref->bar(); // foo::~foo is called for you