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 };
  • Solutions using C++0x are welcome
  • The array may be quite large, few hundred elements long
  • The array for now will only consist of POD types
  • It can also be assumed the size of the array will be known beforehand, in a static compile-time compliant manner.
  • 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.


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

    Well your requirements are so vague it's difficult to do anything about them... The main issue is of course: where do those value come from ?

    Anyway a build in C++ can be thought of as 4 steps:

  • Pre-build steps: script generation of header/source from other formats
  • Preprocessing
  • Template instantiations
  • Compilation proper
  • If you wish to rule out the script generation, then you're left with 2 alternatives: Preprocessing and Meta-template programming.

    There is just no way I know of for meta-template programming to do the trick here, because as far as I know it's not possible to concatenate two arrays at compile time. Thus we are left with the savior of the day: Preprocessor Programming

    I would suggest using a full-fledged library to help us out: Boost.Preprocessor.

    Of particular interest here:

  • BOOST_PP_FOR
  • BOOST_PP_REPEAT
  • Now if only we knew where to pick the values from, we could give more meaningful examples.


    How about building a nested struct using templates, and casting that as an array of the right type. The example below works for me, but I have a feeling I'm either treading in or walking very close to undefined behaviour.

    #include <iostream>
    
    template<int N>
    struct NestedStruct
    {
      NestedStruct<N-1> contained;
      int i;
      NestedStruct<N>() : i(N) {}
    };
    
    template<>
    struct NestedStruct<0> 
    {
      int i;
      NestedStruct<0>() : i(0) {}
    };
    
    int main()
    {
      NestedStruct<10> f;
      int *array = reinterpret_cast<int*>(&f);
      for(unsigned int i=0;i<10;++i)
      {
        std::cout<<array[i]<<std::endl;
      }
    }
    

    And of course you could argue that the array is not initialised at compile time (which I think is impossible) but the values that will go into the array are calculated at compile time, and you can access them as you would a normal array... I think that's as close as you can get.

    链接地址: http://www.djcxy.com/p/62690.html

    上一篇: 使用c ++模板的2s电源阵列

    下一篇: 以编程方式在C ++中以编程方式创建静态数组