How to Create and Initialize an Array of Values Using Template Metaprogramming

Is it possible to create and initialize an array of values using template metaprogramming?

Although you can't initialise an array in-place like that, you can do almost the same thing by creating a recursive struct:

template <int I>
struct squared {
squared<I - 1> rest;
int x;
squared() : x((I - 1) * (I - 1)) {}
};

template <>
struct squared<1> {
int x;
squared() : x(0) {}
};

Then later in your code you can declare:

squared<5> s;

and the compiler will indeed create a struct containing 5 ints: 0, 1, 4, 9, 16.

A couple of notes:

  1. My interpretation of the C++ standard is that it stops short of guaranteeing that this struct will be laid out identically to an array. While it is a POD type, and POD types are guaranteed to be laid out "contiguously" in memory (1.8/5) with the first member at offset 0 (9.2/17) and later members at higher addresses (9.2/12), and arrays are also laid out "contiguously" (8.3.4/1), the standard doesn't say that arrays are layout-compatible with such structs. However, any sane compiler will lay these objects out identically. [EDIT: As ildjarn points out, the presence of a user-defined constructor actually makes this class non-aggregate and therefore non-POD. Again, any sane compiler will not allow this to affect its layout.]
  2. C++ requires that even an empty struct be at least 1 byte long. If it did not, we could go with a slightly cleaner formulation in which the base case of the recursion was I == 0 and we didn't subtract 1 from I for the calculations.

It would be nice if we could place this struct inside a union with an array of the appropriate size, to make it easy to access the members. Unfortunately, C++ bans you from including an object in a union if that object has a non-trivial constructor. So the easiest way to get at the ith element is with a good old-fashioned cast:

squared<5> s;
cout << "3 squared is " << reinterpret_cast<int*>(&s)[3] << endl;

If you wanted, you could write an overloaded operator[]() function template to make this prettier.

fill static templated arrays with metaprogramming and variadic templates

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

Programmatically create static arrays at compile time in C++

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

incrementally create arrays at compile time

Can you help me out here? Why isn't it deducible? I wrote '-1'!

The compiler cannot deduce idx exactly because you wrote -1. Since you're explicitly specifying what idx should be, you should get rid of it from the template parameters:

template<typename T, T... values> struct IncSeq<-1, T, values...> : Seq<T, values...> {};

You also need to expand values here:

template<typename T, T... values>
const T Seq<T, values...>::value[] = { values... };

Your code will now compile. (I have not tested the correctness of your solution.)

live wandbox example

Sequence array initialization with template

I'm not sure if this meets your requirements.

#include <array>
#include <iostream>

template <size_t ...I>
constexpr auto init(std::index_sequence<I...>) {
return std::array<size_t, sizeof...(I)>{I...};
}

int main(void)
{
std::array<size_t, 10> a = init(std::make_index_sequence<10>());

for (int const & i : a)
std::cout << i << "\n";
return 0;
}

Function array initialization at compile time with metaprograming

I achieved it based on Kal answer of a similar problem
Create N-element constexpr array in C++11

template <int S>
struct Foo{
static void LoadingStep()
{
}
};

template <>
struct Foo<0>
{
static void LoadingStep()
{
//First loading step

}
};

template<template<int S> class T,int N, int... Rest>
struct Array_impl {
static constexpr auto& value = Array_impl<T,N - 1, N, Rest...>::value;
};

template<template<int S> class T,int... Rest>
struct Array_impl<T,0, Rest...> {
static constexpr std::array<void*,sizeof...(Rest)+1> value = {reinterpret_cast<void*>(T<0>::LoadingStep),reinterpret_cast<void*>(T<Rest>::LoadingStep)...};
};

template<template<int S> class T,int... Rest>
constexpr std::array<void*,sizeof...(Rest)+1> Array_impl<T,0, Rest...>::value;

template<template<int S> class T,int N>
struct F_Array {
static_assert(N >= 0, "N must be at least 0");

static constexpr auto& value = Array_impl<T,N>::value;

F_Array() = delete;
F_Array(const F_Array&) = delete;
F_Array(F_Array&&) = delete;
};

Using example:

int main()
{
auto& value = F_Array< Foo ,4>::value;
std::cout << value[0] << std::endl;

}

This yields of void* array of pointers to template functions:

Foo<0>::LoadinStep()
Foo<1>::LoadinStep()
Foo<2>::LoadinStep()
Foo<3>::LoadinStep()
Foo<4>::LoadinStep()

Since Foo<1..3> are not specialized they will fall to Default LoadingStep function

Initialize constexpr array with template functions

Have you tried the solution based over std::make_index_sequence/std::index_sequence ?

template <std::size_t ... Is>
constexpr std::array<IntExecutor, sizeof...(Is)>
makeLutHelper (std::index_sequence<Is...>)
{ return { func<int(Is)>... }; }

template <std::size_t N>
constexpr auto makeLut ()
{ return makeLutHelper(std::make_index_sequence<N>{}); }

I can't test it with MSVC but, in my Linux platform, g++ and clang++ compile also (with long, long time)

constexpr auto lut = makeLut<0x10000u>();

How to initialize a template sized array?

You could just keep adding one this at a time until you have N of them, at which point you just initialize _array:

    Foo()
: Foo(this)
{ }

private:
template <class... T, std::enable_if_t<(sizeof...(T) < N), void*> = nullptr>
Foo(T... args)
: Foo(args..., this)
{ }

template <class... T, std::enable_if_t<(sizeof...(T) == N), void*> = nullptr>
Foo(T... args)
: _array{{args...}}
{ }

Concisely declare and initialize a multi-dimensional array in C++

It's possible with template metaprogramming.

Define a vector NVector

template<int D, typename T>
struct NVector : public vector<NVector<D - 1, T>> {
template<typename... Args>
NVector(int n = 0, Args... args) : vector<NVector<D - 1, T>>(n, NVector<D - 1, T>(args...)) {
}
};

template<typename T>
struct NVector<1, T> : public vector<T> {
NVector(int n = 0, const T &val = T()) : vector<T>(n, val) {
}
};

You can use it like this

    const int n = 5, m = 5, k = 5;
NVector<3, int> a(n, m, k, 0);
cout << a[0][0][0] << '\n';

I think it's clear how it can be used. Let's still say NVector<# of dimensions, type> a(lengths of each dimension separated by coma (optional)..., default value (optional)).

Creating an array initializer from a tuple or variadic template parameters

In order for compile time accumulation to occur, you have to have a compile time sequence.

An easy way to do this would be to use variadic templates. Each entry would be an identifier and a size of a particular element, or the identifier and type of a particular element.

The top level bundle of entries would be a Layout:

template<std::size_t offset, typename Key, typename... Entries>
struct LayoutHelper {
typedef std::tuple<> type;
};
template<typename Key, typename... Entries>
struct Layout:LayoutHelper<0, Key, Entries...> {};

Each entry would be:

template<typename Key, Key identifier, typename Data>
struct Entry {};

Then, we do something like this:

template<typename Key, Key identifier, typename Data, std::size_t Offset>
struct ProcessedEntry {};

template<std::size_t offset, typename Key, Key id0, typename D0, typename... Entries>
struct LayoutHelper<offset, Key, Entry<Key, id0, D0>, Entries...>
{
typedef typename prepend
< ProcessedEntry< Key, id0, D0, offset >
, typename LayoutHelper<offset+sizeof(D0), Key, Entries...>::type
>::type type;
};

Use would look like:

Layout< FooEnum, Entry< FooEnum, eFoo, char[10] >, Entry< FooEnum, eFoo2, double > > layout;

which, after writing or finding a prepend that takes an element and a tuple, and prepends the element at the front, would mean that Layout<blah>::type would contain a tuple that describes the layout of your data.

template<typename T, typename Pack>
struct prepend;
template<typename T, template<typename...>class Pack, typename... Ts>
struct prepend<T, Pack<Ts...>> {
typedef Pack<T, Ts...> type;
};
// use: prepend<int, std::tuple<double>::type is std::tuple<int, double>
// this removes some ::type and typename boilerplate, if it works in your compiler:
template<typename T, typename Pack>
using Prepend = typename prepend<T, Pack>::type;

You'd then unpack that tuple into a std::array if you wanted. You'd use the indexes trick to do this (there are many examples on stack overflow that use this same trick in different ways).

Or, you could take your ProcessedEntry and add in methods to access data, then write a Key searching compile-time program that walks the tuple, looking for the matching Key, and then returns the offset and size (or even type) as compile time code. Maybe take an array<N, unsigned char> as an argument and do the reintepret_cast, returning a reference-to-data.

Removing the repeated FooEnum would be good via using aliases.



Related Topics



Leave a reply



Submit