1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
/*
   The Table template class helps to construct constexpr arrays
   of unsigned int values that support random-access using indices
   computed at runtime.

   Example:

      #include <iostream>
      #include "Table.hpp"

      template<unsigned int I>
      struct ComputeSquare {
     static constexpr unsigned int value = I * I;
      };

      constexpr unsigned int N = 10;
      using Squares = Table<N, ComputeSquare>;

      int main() {
     for (unsigned int i = 0; i < N; ++i) {
        std::cout << Squares::val[i] << std::endl;
     }
      }
*/

#ifndef TABLE_HPP
#define TABLE_HPP

/* helper template for the Table template to
   construct an constexpr array filled with values
   F<0>::value .. F<N-1>::value;
   this template works recursively, i.e.
    - F<I+1>::value ... F<N>::value have already been computed and
      are passed as unsigned int ... values
    - F<0>::value ... F<I>::value are to be computed
*/
template<unsigned int I, unsigned int N, template<unsigned intclass F,
   unsigned int ... values>
struct TableConstructor;

/* this special case with I == 0 ends the recursion,
   i.e. we insert F<0>::value in front of values...
   which represent F<1>::value ... F<N-1>::value */
template<unsigned int N, template<unsigned intclass F,
       unsigned int ... values>
struct TableConstructor<0, N, F, values...> {
   static constexpr unsigned int len = N;
   typedef unsigned int type[len];
   /* note that the static member val is defined below
      at the end of this header file */
   static constexpr type val = {F<0>::value, values...};
};

/* recursive case with I > 0 where
    - values... represent F<I+1>::value ... F<N-1>::value and
    - F<I>::value is inserted in the front */
template<unsigned int I, unsigned int N, template<unsigned intclass F,
   unsigned int ... values>
struct TableConstructor :
   public TableConstructor<I-1, N, F, F<I>::value, values...> {
};

/* Table is used to create a constexpr table with N elements
   that is filled with the values F<0>::value to F<N-1>::value
   using the TableConstructor helper template */
template<unsigned int N, template<unsigned intclass F>
struct Table : public TableConstructor<N-1, N, F> {
};

/* definition of the static member val of the TableConstructor template;
   if we do not have this, we have no support for a random access
   of the table with indices computed at runtime */
template<unsigned int N, template<unsigned intclass F,
       unsigned int ... values>
constexpr typename TableConstructor<0, N, F, values...>::type
   TableConstructor<0, N, F, values...>::val;

#endif