Let's say I have a type which is neither movable nor copyable:
struct foo
{
explicit foo( size_t ){}
~foo(){}
foo( foo const & ) = delete;
foo( foo && ) = delete;
foo& operator=( foo const & ) = delete;
foo& operator=( foo & ) = delete;
};
Now given a number known at compile time (call it N), is there any way that I can create a "sequence" of these on the stack with each one initialized with numbers 0 through N-1? I would be satisfied with a C-style array foo[N]
, a std::array< foo, N >
, or perhaps even a std::tuple
of some kind.
What I'm trying to avoid is writing out:
foo f0( 0 ), f1( 1 ), ... fNminus1( N-1 );
when it feels like this is something the compiler should be able to do for me. The best I've been able to come up with is using boost::optional
.
boost::optional< foo > f[N];
for( size_t i = 0U; i < N; ++i )
f[i] = boost::in_place( i );
But that relies on runtime logic even though all the required information is available at compile-time. Plus, I'm left with something that behaves like an array of pointers.
// 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();
If that seems like a lot of hassle, it is. But you could easily encapsulate that functionality in a class.
Although not strictly an array, you can sort of accomplish this with template recursion
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;
}
};
Usage:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With