One can define a static array at compile time as follows:
const std::size_t size = 5; unsigned int list[size] = { 1, 2, 3, 4, 5 };
Question 1 - Is it possible by using various kinds of metaprogramming techniques to assign these values "programmatically" at compile time?
Question 2 - Assuming all the values in the array are to be the same barr a few, is it possible to selectively assign values at compile time in a programmatic manner?
eg:
const std::size_t size = 7; unsigned int list[size] = { 0, 0, 2, 3, 0, 0, 0 };
UPDATE: Georg Fritzsche's solution is amazing, needs a little work to get it compiling on msvc and intel compilers, but nonetheless a very interesting approach to the problem.
One can define a static array at compile time as follows: const std::size_t size = 5; unsigned int list[size] = { 1, 2, 3, 4, 5 };
If the array has static storage duration (meaning it was declared at file scope outside of any function body, or was declared with the static keyword) and no initializer is present, then all of the array elements are initialized to 0 (for scalars) or NULL (for pointers).
Run time Array initializationUsing runtime initialization user can get a chance of accepting or entering different values during different runs of program. It is also used for initializing large arrays or array with user specified values. An array can also be initialized at runtime using scanf() function.
With the MicroC profile, you can specify that elements should be initialized at compile time. Compile-time initialization provides the following benefits: Ability to allocate data to ROM. Saving of CPU cycles at application startup. Ability to allocate data to specific memory segments.
The closest you can get is using C++0x features to initialize local or member arrays of templates from a variadic template argument list.
This is of course limited by the maximum template instantiation depth and wether that actually makes a notable difference in your case would have to be measured.
Example:
template<unsigned... args> struct ArrayHolder { static const unsigned data[sizeof...(args)]; }; template<unsigned... args> const unsigned ArrayHolder<args...>::data[sizeof...(args)] = { args... }; template<size_t N, template<size_t> class F, unsigned... args> struct generate_array_impl { typedef typename generate_array_impl<N-1, F, F<N>::value, args...>::result result; }; template<template<size_t> class F, unsigned... args> struct generate_array_impl<0, F, args...> { typedef ArrayHolder<F<0>::value, args...> result; }; template<size_t N, template<size_t> class F> struct generate_array { typedef typename generate_array_impl<N-1, F>::result result; };
Usage for your 1..5
case:
template<size_t index> struct MetaFunc { enum { value = index + 1 }; }; void test() { const size_t count = 5; typedef generate_array<count, MetaFunc>::result A; for (size_t i=0; i<count; ++i) std::cout << A::data[i] << "\n"; }
Since C++17 you can use a constexpr
lambda an invoke it in place. The only "downside" is that you will have to use std::array
instead of c-style array:
constexpr auto myArray{[]() constexpr{ std::array<MyType, MySize> result{}; for (int i = 0; i < MySize; ++i) { result[i] = ... } return result; }()};
As an example that's how you could create an array with powers of two:
constexpr auto myArray{[]() constexpr{ constexpr size_t size = 64; std::array<long long, size> result{}; result[0] = 1; for (int i = 1; i < size; ++i) { result[i] = result[i - 1] * 2; } return result; }()};
As you can see, you can even reference the previous cells of the array.
This technique is called IILE or Immediately Invoked Lambda Expression.
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