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 int
s: 0, 1, 4, 9, 16.
A couple of notes:
- 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 suchstruct
s. 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.] - 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 wasI == 0
and we didn't subtract 1 fromI
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 i
th 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
Delete All Items from a C++ Std::Vector
Why Do C++ Streams Use Char Instead of Unsigned Char
Pointing to a Function That Is a Class Member - Glfw Setkeycallback
C++, How to Call a Constructor Directly, Without New
What Are Customization Point Objects and How to Use Them
Function Pointers in Objective C
Cross-Platform Iteration of Unicode String (Counting Graphemes Using Icu)
How to Sleep or Pause a Pthread in C on Linux
Qt: How to Handle the Event of the User Pressing the 'X' (Close) Button
Qt Qwebenginepage::Setwebchannel() Transport Object
C++11 Is_Same Type Trait for Templates
Using Emit VS Calling a Signal as If It's a Regular Function in Qt
Can You Allocate a Very Large Single Chunk of Memory ( > 4Gb ) in C or C++
C++ Objects: When Should I Use Pointer or Reference