Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically create static arrays at compile time in C++

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 }; 
  1. Solutions using C++0x are welcome
  2. The array may be quite large, few hundred elements long
  3. The array for now will only consist of POD types
  4. It can also be assumed the size of the array will be known beforehand, in a static compile-time compliant manner.
  5. Solutions must be in C++ (no script, no macros, no pp or code generator based solutions pls)

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.

like image 821
Hippicoder Avatar asked Jun 04 '10 22:06

Hippicoder


People also ask

How do you declare an array in compile time?

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 };

Can we declare array as static in C?

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).

What is run time initialization of array in C?

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.

What does it mean to perform a compile time initialization of an array?

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.


2 Answers

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"; } 
like image 125
Georg Fritzsche Avatar answered Sep 20 '22 16:09

Georg Fritzsche


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.

like image 23
janekb04 Avatar answered Sep 19 '22 16:09

janekb04