fill static templated arrays with metaprogramming and variadic templates - c++

I know that there are easier ways to do it, but
I would like to initialize at compilation time
the map from unrolled index of 2d array to its general format.
I would like to do this without needing to instansiate the array object.
Below I define the map from array[][]->array[].
Now I wonder how to do the opposite: [] -> [][]
without hardcoding the chosen mapping scheme.
I guess that should be possible using metaprogramming and variadic templates.
But I tried using it for the first time just a couple of days ago,
so it takes a while to get used to ;)
header:
template <int dim>
class internal {
static unsigned int table[dim][dim];
static unsigned int x_comp[dim*dim];
static unsigned int y_comp[dim*dim];
};
source:
//1d case:
template <>
unsigned int
internal<1>::table[1][1] = {{0}};
template <>
unsigned int
internal<1>::x_component[1] = {0};
template <>
unsigned int
internal<1>::y_component[1] = {0};
//2d case:
template<>
unsigned int
internal<2>::table[2][2] =
{{0, 1},
{2, 3}
};
// here goes some metaprogramming tricks to initialize
// internal<2>::y_component[2*2] = ...
// internal<2>::x_component[2*2] = ...
// based on mapping above, i.e. table[2][2];
// that is:
// x_table = { 0, 0, 1, 1 }
// y_table = { 0, 1, 0, 1 }
//
// so that :
//
// index == table[i][j]
// i == x_comp[index]
// j == y_comp[index]
EDIT1:
or just tell me that it's not possible and I hard-code everything or use
integer division to relate the two index representations.
EDIT2:
i would prefer to stick with definition of arbitrary arrays.
Of course one can do without, as in answer below using integer division.
Those arrays can be really arbitrary, for example:
template<>
unsigned int
internal<2>::table[2][2] =
{{3, 0},
{2, 1}
};

Using arrays:
Given a table with unique entries from 0 to dim^2-1, you can write constexpr lookup functions for the i and j of a given table entry:
constexpr unsigned get_x_comp(unsigned index, unsigned i=0, unsigned j=0)
{ return table[i][j] == index ? i : get_x_comp(index, ((j+1)%dim ? i : i+1), (j+1)%dim); }
constexpr unsigned get_y_comp(unsigned index, unsigned i=0, unsigned j=0)
{ return table[i][j] == index ? j : get_y_comp(index, ((j+1)%dim ? i : i+1), (j+1)%dim); }
These will recursively call themselves, iterating through the table and looking for index. Recursion will eventually end when the given index is found and i/j of that index is returned.
Combine that with the C++14 std::integer_sequence mentioned by Jonathan to initialize the arrays:
template<unsigned... I>
constexpr auto make_x_comp(std::integer_sequence<unsigned, I...>) -> std::array<unsigned, sizeof...(I)> { return {get_x_comp(I)...}; }
Using metafunctions instead of arrays:
In some cicumstances, one might not even need arrays. I assume you want to the table to contain consecutive indices from 0 to dim^2-1. If that's the case, table, x_comp and y_comp are only simple compiletime functions with the following attributes:
table(i,j) := i*dim + j
x_comp(index) := index / dim (integer division)
y_comp(index) := index % dim
Depending on if you have C++11 features available, the implementation will be different, but both times without arrays.
Note: the following implementations will assume that the numbers stored in table are consecutive from 0 to dim^2-1. If that is not the case, you'll have to roll your own appropiate function for table and use the above get_x_comp and get_y_comp implementatio
C++11:
template <unsigned dim> //use unsigned to avoid negative numbers!
struct internal {
static constexpr unsigned table(unsigned i, unsigned j) { return i*dim+j; }
static constexpr unsigned x_comp(unsigned index) { return index/dim; }
static constexpr unsigned y_comp(unsigned index) { return index%dim; }
};
You can call these functions like normal functions anywhere, especially anywhere you need compiletime constants. Example: int a[internal<5>::table(2,4)];
C++03:
template <unsigned dim> //use unsigned to avoid negative numbers!
struct internal {
template<unsigned i, unsigned j>
struct table{ static const unsigned value = i*dim+j; };
template<unsigned index>
struct x_comp{ static const unsigned value = index/dim; };
template<unsigned index>
struct y_comp{ static const unsigned value = index%dim; };
};
Using these metafunctions is a bit more clumsy than in C++11, but works as usual with template metafunctions. Same example as above: int a[internal<5>::table<2,4>::value];
Note: This time you can put the (meta-)functions in the header, since they are not non-integral static member variables any more. Also you do not need to restrict the template to small dimensions, since everything will be calculated well for dimensions less than sqrt(numeric_limits<unsigned>::max()).

I'm sorry if I'm not answering the question directly (or at all), but I don't really understand what you're asking. I think what you're saying is that you want to initialize at compilation time a way to have an array of size N x M represented as a 1D array?
I've included code that allows you to allocate non-square dimensions. I've built this in "easy" C++ so if you're just getting into templates it's not so difficult to follow.
Is it possible to do something like this?
template <typename T, typename std::size_t N, typename std::size_t M = 1>
class Array {
T* data;
public:
Array<T, N, M>() : data(new T[N * M]) {
T temp = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
data[i * M + j] = temp++;
}
}
}
/* methods and stuff
}
Where M is the column number, so you'd use this like:
int main(void) {
Array<float, 10, 10> myArray;
return 0;
}
Remember to call delete in the destructor.

Edit: I didn't understand the rule for populating x_comp and y_comp when I wrote this, now that I see that part of the question this answer is not really relevant, because I was incorrectly assuming table only contained consecutive integers. The answer is left here anyway because Arne's (much better) answer refers to it.
I would replace the arrays with std::array and use the C++14 integer_sequence utility:
template <int dim>
struct internal {
static std::array<std::array<unsigned, dim>, dim> table;
static std::array<unsigned, dim*dim> x_comp;
static std::array<unsigned, dim*dim> y_comp;
};
template<unsigned Origin, unsigned... I>
constexpr std::array<unsigned, sizeof...(I)>
make_1d_array_impl(std::integer_sequence<unsigned, I...>)
{
return { { I + Origin ... } };
}
template<int N>
constexpr std::array<unsigned, N*N>
make_1d_array()
{
return make_1d_array_impl<0>(std::make_integer_sequence<unsigned, N*N>{});
}
template<unsigned... I>
constexpr std::array<std::array<unsigned, sizeof...(I)>, sizeof...(I)>
make_2d_array_impl(std::integer_sequence<unsigned, I...> seq)
{
return { { make_1d_array_impl<I*sizeof...(I)>(seq) ... } };
}
template<int N>
constexpr std::array<std::array<unsigned, N>, N>
make_2d_array()
{
return make_2d_array_impl(std::make_integer_sequence<unsigned, N>{});
}
template<int dim>
std::array<std::array<unsigned, dim>, dim> internal<dim>::table = make_2d_array<dim>();
That fills the table array correctly. I'll have to think about it a bit more to populate x_comp and y_comp as you want, but it's doable.
You can find an C++11 implementation of integer_sequence at https://gitlab.com/redistd/integer_seq/blob/master/integer_seq.h

Related

How to find size of multidimensional std::array?

I am having a multidimensional std::array and looking for the proper (convenient and efficient) way to find its size (in number of cells or in bytes)
size() returns only the last dimension size (which is understood)
std::array<std::array<std::array<std::array<double, 2>, 3>, 6>, 100> my_array;
my_array.size(); // returns 100
Although the size of the array is known in compile time, I wish to avoid #define SIZE_OF_MY_ARRAY or a global variable because, I am looking for a better way than passing the size with the array (as in "old" arrays, not std array), or informing others to use the defined term.
I also prefer no to calculate it every time.
Perhaps these 2 preferences are not possible for multidimensional array?
How can I efficiently find the overall size of my_array? I am using c++11.
It's not too hard to write a small utility that calculates this at compile time.
template<typename T> struct arr_sz {
static constexpr std::size_t size = sizeof(T);
};
template<typename T, std::size_t N>
struct arr_sz<std::array<T, N>> {
static constexpr std::size_t size = N * arr_sz<T>::size;
};
The above should unravel a nested array definition of any practical depth, and evaluate to the size in bytes used for storing T's, with all potential padding excluded.
An example of using it would be
std::array<std::array<std::array<std::array<double, 2>, 3>, 6>, 100> my_array;
constexpr auto sz = arr_sz<decltype(my_array)>::size;
static_assert(sz == sizeof(double) * 2 * 3 * 6 * 100, "");
That you may see live.
How about
sizeof(my_array)/sizeof(double);
You can use a recursion to calculate its size:
template<typename T>
size_t get_array_full_size(T &val) { // for the last array type (double in this case)
return 1;
}
template<typename T, size_t Len>
size_t get_array_full_size(std::array<T, Len> &arr) {
return get_array_full_size(arr[0]) * arr.size();
}
int main() {
std::array<std::array<std::array<std::array<double, 2>, 3>, 6>, 100> my_array;
std::cout << get_array_full_size(my_array) << std::endl;
return 0;
}
You could use constexpr variables that bind to the dimensions and then use those to compute the desired quantity.
constexpr int n1 = 2;
constexpr int n2 = 3;
constexpr int n3 = 6;
constexpr int n4 = 100;
std::array<std::array<std::array<std::array<double, n1>, n2>, n3>, n4> my_array;
constexpr int myArraySize = n1*n2*n3*n4;
Something similar to #KorelK 's approach. Recursive template function will stop when
class template of std::array is primitive type.
(See online)
#include <array>
#include <type_traits> // std::is_fundamental_v
template<typename Type, std::size_t N>
std::size_t overall_size(const std::array<Type, N>&)
{
if constexpr(std::is_fundamental_v<Type>) return N;
else return N * overall_size(Type{});
}

Pass N-D array by reference to variadic function

I'd like to make the function multi_dimensional accept a multidimensional array by reference.
Can this be done with a variation of the syntax below which works for three_dimensional?
#include <utility>
// this works, but number of dimensions must be known (not variadic)
template <size_t x, size_t y, size_t z>
void three_dimensional(int (&nd_array)[x][y][z]) {}
// error: parameter packs not expanded with ‘...’
template <size_t... dims>
void multi_dimensional(int (&nd_array)[dims]...) {}
int main() {
int array[2][3][2] = {
{ {0,1}, {2,3}, {4,5} },
{ {6,7}, {8,9}, {10,11} }
};
three_dimensional(array); // OK
// multi_dimensional(array); // error: no matching function
return 0;
}
The main problem is that you cannot make the number of array dimensions itself variadic. So whichever way you go, you will almost certainly need a recursive approach of some sort to deal with the individual array layers. What exactly such approach should look like will mainly depend on what exactly you're planning to do with the array once it's been given to you.
If really all you want is a function that can be given any multi-dimensional array, then just write a function that can be given anything but only exists as long as that anything is an array:
template <typename T>
std::enable_if_t<std::is_array_v<T>> multi_dimensional(T& a)
{
constexpr int dimensions = std::rank_v<T>;
// ...
}
However, this by itself will most likely not get you very far. To actually do anything meaningful with the array you've been given, you will most likely need some recursive walking through subarrays. Unless you really just want to look at the topmost layer of the structure.
Another approach is to use a recursive template to peel back the individual array levels, for example:
// we've reached the bottom
template <typename T, int N>
void multi_dimensional(T (&a)[N])
{
// ...
}
// this matches any array with more than one dimension
template <typename T, int N, int M>
void multi_dimensional(T (&a)[N][M])
{
// peel off one dimension, invoke function for each element on next layer
for (int i = 0; i < N; ++i)
multi_dimensional(a[i]);
}
I would, however, suggest to at least consider using std::array<> instead of raw arrays as the syntax and special behavior of raw arrays tends to turn everything into a confusing mess in no time. In general, it might be worth to implement your own multi-dimensional array type, like an NDArray<int, 2, 3, 2> which internally works with a flattened representation and just maps multi-dimensional indices to a linear index. One advantage of this approach (besides the cleaner syntax) would be that you can easily change the mapping, e.g., to switch from row-major to column-major layout, e.g., for performance optimization…
To implement a general nD array with static dimensions, I would introduce a helper class to encapsulate the recursive computation of a linear index from an nD index:
template <std::size_t... D>
struct row_major;
template <std::size_t D_n>
struct row_major<D_n>
{
static constexpr std::size_t SIZE = D_n;
std::size_t operator ()(std::size_t i_n) const
{
return i_n;
}
};
template <std::size_t D_1, std::size_t... D_n>
struct row_major<D_1, D_n...> : private row_major<D_n...>
{
static constexpr std::size_t SIZE = D_1 * row_major<D_n...>::SIZE;
template <typename... Tail>
std::size_t operator ()(std::size_t i_1, Tail&&... tail) const
{
return i_1 + D_1 * row_major<D_n...>::operator ()(std::forward<Tail>(tail)...);
}
};
And then:
template <typename T, std::size_t... D>
class NDArray
{
using memory_layout_t = row_major<D...>;
T data[memory_layout_t::SIZE];
public:
template <typename... Args>
T& operator ()(Args&&... args)
{
memory_layout_t memory_layout;
return data[memory_layout(std::forward<Args>(args)...)];
}
};
NDArray<int, 2, 3, 5> arr;
int main()
{
int x = arr(1, 2, 3);
}

Programmatic initialization of a long array at compile or initialization time

Here is a code snippet illustrating my question:
const float D = 0.1F;
const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)};
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time, i.e. without having to write initialization function and call it somewhere in my program?
You could initialize A during dynamic initialization time as follows:
const float *init_a(float x_)
{
static float data[4];
for(unsigned i=0; i<4; ++i)
data[i]=sin(i*x_);
return data;
}
const float D=0.1f;
const float *A=init_a(D);
You may use code generator to generate initialization code. That is, write program that will write your initialization code for you. You may actually calculate values at generation-time.
Remember that C++ allows placing , after last element. It's also isn't necessary to specify array size. These two things should ease writing of generator.
This simple python code should work well:
from math import sin
print('const float A[', N, '] = {')
for i in range(N):
print('\t', sin(i*D), ',', sep='')
print('};')
Ok I just realized this doesn't actually answer the question, because it specifies "without having to write initialization function and call it somewhere in my program?" But I can't think of a convenient alternative.
template<size_t N>
std::array<float, N> GetLookupTable(float d)
{
std::array<float, N> table;
// .. populate table here
return table;
}
// a global somewhere
(static?) const auto Table_10x5 = GetLookupTable<10>(5.0f);
This first part is obsolete in C++14, but not long:
template<unsigned...>struct indexes { using type=indexes; };
template<unsigned Max, unsigned...Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
this is some template meta programming that lets us create and pass around bundles of indexes.
Then some code to generate the array:
namespace details {
template<std::size_t N, unsigned...Is>
std::array<float, N> poly_sin(float src, indexes<Is...>) {
return { (Is*sin(src))... };
}
}
template<std::size_t N>
std::array<float, N> poly_sin(float src) {
return details::poly_sin<N>( src, make_indexes_t<N>{} );
}
The first method takes indexes<Is...> and we plan that Is... is 0, 1, 2, ..., N-1. It then expands the parameter pack into a std::array of the right size.
make_indexes_t<N>{} expands (at compile time) to indexes<0, 1, 2, ..., N-1>{}, which is then passed to details::poly_sin, which then can deduce the Is... and use them within itself.
And point of use:
const float D = 0.1F;
const auto A = poly_sin<4>(D);
if you had a constexpr sin function, you could even make poly_sin a constexpr function and have it basically guaranteed to be evaluated at compile time.
If this is the case, make D constexpr and same with the two poly_sin functions.
As written, this occurs at dynamic initialization time.
While it appears that the array is copied twice, RVO elision means that any decent compiler will directly construct it in A.
If you want to be able to do this in general, first start with the above indexes code. Then add this:
template<class Sig>using result_of_t=typename std::result_of<Sig>::type;
namespace details {
template<std::size_t N, class F, unsigned... Is>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f, indexes<Is...> ) {
return { f( Is )... };
}
}
template<std::size_t N, class F>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f ) {
return details::make_array( std::forward<F>(f), make_indexes_t<N>{} );
}
const auto A = make_array<4>( [](unsigned i){ return float(i*sin(D)); } );
which uses a lambda to pass in the code that is repeated to build the array. Sadly, lambdas are not by default constexpr so you cannot do it at compile time.
You could either use boost.preprocessor and in particular the BOOST_PP_ENUM macro, like the example below:
#include <iostream>
#include <cmath>
#include <boost/preprocessor/repetition/enum.hpp>
#define SIZE 4
#define D 0.1
#define ORDER(z, n, text) std::sin(n * D)
double const A[SIZE] = { BOOST_PP_ENUM(SIZE, ORDER, ~) };
int main() {
for(auto i : A) std::cout << i << std::endl;
}
Or, you could use std::array instead of raw arrays, and via use of template meta-programming to generate a std::array at compile time. like the example below:
template<typename T, typename F, int SIZE, int... N>
constexpr std::array<T, SIZE>
genarray(F f) {
return std::array<T, SIZE>{{ f(N)... }};
}
template<typename T, typename F, int SIZE, int...> struct recursive_gen;
template<typename T, typename F, int SIZE, int... Args>
struct recursive_gen<T, F, SIZE, 0, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return genarray<T, F, SIZE, 0, Args...>(f);
}
};
template<typename T, typename F, int SIZE, int N, int... Args>
struct recursive_gen<T, F, SIZE, N, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, N - 1, N, Args...>::generate(f);
}
};
template<typename T, int SIZE>
struct array_generator {
template<typename F>
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, SIZE - 1>::generate(f);
}
};
std::array<double, 4> const A = array_generator<double, 4>::generate([](int i) { return std::sin(0.1 * i);});
std::array<double, 4> const B = array_generator<double, 4>::generate([](int i) { return std::cos(0.1 * i);});
constexpr int fun(int i) { return 2 * i; }
constexpr std::array<int, 4> const C = array_generator<int, 4>::generate(fun); // generation during compile time
LIVE DEMO
Note however, that in order for generation to take place at compile time input function in array_generator must be constexpr. This is not the case for trigonometric functions (i.e., they are not constexpr). Thus initialization of arrays A and B will take place at initialization time, whereas generation of array C will take place at compile time.
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time
Create a generator and pass it through std::generate_n() (or plain std::generate()).
#include <algorithm>
#include <array>
#include <cmath>
template <typename Value_t>
struct SinGenerator{
SinGenerator(std::size_t start = 0, Value_t counter_scalar = 1)
: index{start},
scalar{counter_scalar} {
}
Value_t operator()() {
return sin(index++ * scalar);
}
std::size_t index;
Value_t scalar;
};
template <typename Value_t, std::size_t Size>
std::array<Value_t, Size> init_table(const std::size_t start,
const Value_t counter_scalar) {
std::array<Value_t, Size> arr;
SinGenerator<Value_t> gen(start, counter_scalar);
std::generate(arr.begin(), arr.end(), gen);
return arr;
}
const auto kSinTable(init_table<float, 10>(0, 0.1f));
In case you A array will always stays the same and is very big, you can always write a short script, which calculates every value in array and output could be used in source code to have static initialization.
In case formula is simple, even MS Excel could be used to generate that kind of static initialization data.

C++ static const array initialization in template class

I have the following template class:
template <unsigned N>
class XArray {
static const int Xdata[N];
};
I want to initialize the static const array for each XArray<N> I used, for example, let XArray<N>::Xdata = {1, 2, 3, ..., N}. How to make it?
you declared a static const int array in your class,so you must define the static member out of the class declaration,just like this:
template<unsigned N>
class XArray
{
public:
static const int array[N];
};
template<unsigned N>
const int XArray<N>::array[N] = {1,2,3,4,5};
But something you must pay attention to is that: when you use this template you must make sure that the "N" bigger than the number of your initialized array;
EDIT:
It seems someone have already provided the solution for your problem in other question, and the answer is quite the same as mine.
Also, for more generic answer, you can check out answers to this question.
Code
If you don't mind using C++11 features, then variadic templates may come handy:
template <unsigned ...Args>
struct XArrayData
{
static const int Values[sizeof...(Args)];
};
template<unsigned N, unsigned ...Args>
struct _XArrayGenerator
{
typedef typename _XArrayGenerator<N - 1, N, Args...>::Xdata Xdata;
};
template<unsigned ...Args>
struct _XArrayGenerator<1, Args...>
{
typedef typename XArrayData<1, Args...> Xdata;
};
template<unsigned N>
struct XArray
{
typedef typename _XArrayGenerator<N>::Xdata Xdata;
};
template <unsigned ...Args>
const int XArrayData<Args...>::Values[sizeof...(Args)] = { Args... };
Explanation
XArray template struct takes the number of array elements as a template parameter (N). In the compilation time, it uses _XArrayGenerator to generate template paremeter list with N consecutive numbers. It begins with the number N, and then recursively uses itself until it reaches 1. At this point, the template parameter list looks like this:
1, 2, ..., N
The last thing to do is to pass these parameters to XArrayData. The last line of the code (definition of the actual array) uses the parameters to initialize the array.
Usage
for (int i = 0; i < 3; ++i)
cout << XArray<3>::Xdata::Values[i] << endl;
Output:
1
2
3
You can initialize as shown below. See inline comments for my explanation.
template <unsigned N>
class XArray {
private:
static const int Xdata[N];
public:
//I added this for illustration purpose
void print()
{
for (int i = 0; i < N; ++i)
{
std::cout << Xdata[i] << std::endl;
}
}
};
//you can initialize like this
//automatic size counting works with static arrays
//here I initialize with 3 elements
//make sure you don't use N < 3 anywhere
template <unsigned N>
const int XArray<N>::Xdata[] = {1,2,3};
int main(void)
{
XArray<3> obj1; //N = 3: This is okay.
XArray<8> obj2; //N > 3: This is okay. Remaining elements will be 0.
XArray<2> obj3; //N < 3: This is also okay.
obj1.print();
obj2.print();
obj3.print(); //but this will give compilation error
return 0;
}

Is there a better way to fill array with precalculated values by templates (for using in runtime)?

So, assume I have a template structure-function fib<i>::value. I want to get nth fibonacci number in runtime. For this i create array fibs[] = { fib<0>::value, ... , fib<maxN>::value }. Unfortunatelly, for some functions maxN can be very large and I can't fill it with hands only. So I writed some preprocessor directives to make task easier.
#define fib(x) (fib<(x)>::value)
#define fibLine_level_0(x) fib(5*(x) + 0), fib(5*(x) + 1), fib(5*(x) + 2), fib(5*(x) + 3), fib(5*(x) + 4)
#define fibLine_level_1(x) fibLine_level_0(2*(x) + 0), fibLine_level_0(2*(x) + 1)
#define fibLine_level_2(x) fibLine_level_1(2*(x) + 0), fibLine_level_1(2*(x) + 1)
#define fibLine_level_3(x) fibLine_level_2(2*(x) + 0), fibLine_level_2(2*(x) + 1)
#define cAarrSize(x) (sizeof(x) / sizeof(x[0]))
And I use it so:
int fibs[] = { fibLine_level_3(0) };
for (int i = 0; i < cAarrSize(fibs); i++)
cout << "fib(" << i << ") = " << fibs[i] << endl;
The code that you may need:
template<int i>
struct fibPair{
static const int fst = fibPair<i-1>::snd;
static const int snd = fibPair<i-1>::fst + fibPair<i-1>::snd;
};
template<>
struct fibPair<0> {
static const int fst = 0;
static const int snd = 1;
};
template<int i>
struct fib {
static const int value = fibPair<i>::fst;
};
But this code is really ugly. What to do to make it more beautiful?
Constraints: this code must be used in sport programming. That means - no third-party libraries and sometimes no C++11 (but it can be)
Fib structure can be rewritten as follows:
template <size_t i>
struct fib
{
static const size_t value = fib<i - 1>::value + fib<i - 2>::value;
};
template <>
struct fib<0>
{
static const size_t value = 0;
};
template <>
struct fib<1>
{
static const size_t value = 1;
};
Compile-time array of the Fibonacci numbers can be calculated using C++11.
Edit 1 (changed the type of fib values).
Edit 2:
Compile-time generation of Fibonacci numbers array (based on this answer).
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;
};
int main()
{
const size_t count = 10;
typedef generate_array<count, fib>::result fibs;
for(size_t i = 0; i < count; ++i)
std::cout << fibs::data[i] << std::endl;
}
All you need is to provide generate_array with the generation «function» (our fib struct).
Thanks to #nameless, for giving link to question, where I found answer by #MichaelAnderson for simple c++ (without new features). I used it and expanded for my own needs.
So, concept is simple, but a bit strange. We must produce recursive templated structure, where the first field is this same temlated structure with other argument.
template<size_t N>
struct FibList {
FibList<N-1> previous;
size_t value;
FibList<N>() : value(fib<N>::value) {}
};
Let's try expand it a bit (just to see, what compiler will produce):
template<size_t N>
struct FibList {
FibList<N-3> previous;
size_t value_N_minus_2;
size_t value_N_minus_1;
size_t value_N;
};
So we can think that FibList is array and just cast it (that is weak point of my solution - I can't prove this now)
static const size_t maxN = 2000;
FibList<maxN> fibList;
size_t *fibArray = &fibList.value - maxN;
Or in another way:
size_t *fibArray = reinterpret_cast<size_t*>(&fibList);
Important: size of array is maxN+1, but standart methodic to get array size (sizeof(array) / sizeof(array[0]) will fail. Be pretty accurate with that.
Now we must stop recursion:
// start point
template<>
struct FibList<0> {
size_t value;
FibList<0>() : value(0) {}
};
// start point
template<>
struct FibList<1> {
FibList<0> previous;
size_t value;
FibList<1>() : value(1) {}
};
Note, that swapping places of FibList<1> and FibList<0> will produce stack overflow in compiler.
And we must solve another problem - template recursion have limited depth (depends on compiler and/or options). But, fortunately, compiler have only depth limit, not memory limit for templates (well, yeah, memory limit is more bigger than depth limit). So we have obvious ugly solution - call fib<N> in series with step equal to depth limit - and we will never catch template depth limit about fib<N>. But we can't just write fib<500>::value not in runtime. So we got solution - write macro that will specialize FibList<N> using fib<N>::value:
#define SetOptimizePointForFib(N) template<>\
struct FibList<N> {\
FibList<(N)-1> previous;\
size_t value;\
FibList<N>() : value(fib<N>::value) {}\
};
And we must write something like this:
SetOptimizePointForFib(500);
SetOptimizePointForFib(1000);
SetOptimizePointForFib(1500);
SetOptimizePointForFib(2300);
So we got really compile time precalc and filling static arrays of awesome lengths.