In C++, is there a way to build a compile time list incrementally, in the following pattern?
START_LIST(List)
ADD_TO_LIST(List, int)
ADD_TO_LIST(List, float)
I've found a solution! Though it's just a bit more limited; you need to provide a unique name for each element, and there needs to be an upper limit on the number of elements (here 100).
#include
// Good old Cons and Nil.
template
struct Cons {
using Head = THead;
using Tail = TTail;
};
struct Nil {};
// Helper template which builds a list from a template
// providing elements at given indices.
template class ElemAt, int Offset, int Length>
struct BuildListFromElemAt {
using Result = Cons::Elem, typename BuildListFromElemAt::Result>;
};
template class ElemAt, int Offset>
struct BuildListFromElemAt {
using Result = Nil;
};
// This is where the abuse begins.
// We use these classes to keep the current length
// of the list, in combination with function overloads.
// Each time we add an element, we will provide a more
// specific overload of a helper function.
template
struct Counter : public Counter<(N - 1)> {
static int const Num = N;
};
template <>
struct Counter<0> {
static int const Num = 0;
};
// At the beginning, we define the initial size function
// taking Counter<0>, and declare the ElemAt template.
#define BEGIN_LIST(ListName) \
Counter<0> ListName##_Size (Counter<0>); \
template struct ListName##_ElemAt;
// For each element, we retrieve the current length of the
// list by checking the return type of calling the size function
// with a very large Counter.
// Then we overload the size function for one greater Counter,
// which ensures that we get an incremented length at the next
// step. We also define the ElemAt for this index to return the
// given Value.
#define ADD_TO_LIST(ListName, Name, Value) \
static int const ListName##_##Name##_PrevLen = decltype(ListName##_Size(Counter<100>()))::Num; \
static int const ListName##_##Name##_Len = ListName##_##Name##_PrevLen + 1; \
Counter ListName##_Size (Counter); \
template <> struct ListName##_ElemAt { \
using Elem = Value; \
};
// At the end, we retrieve the final length of the list,
// and build the list using the BuildListFromElemAt template.
#define END_LIST(ListName) \
static int const ListName##_Len = decltype(ListName##_Size(Counter<100>()))::Num; \
using ListName = typename BuildListFromElemAt::Result;
// Here we go...
BEGIN_LIST(List)
ADD_TO_LIST(List, First, int)
ADD_TO_LIST(List, Second, float)
ADD_TO_LIST(List, Third, double)
END_LIST(List)
// And it works :)
static_assert(std::is_same::value, "");
static_assert(std::is_same::value, "");
static_assert(std::is_same::value, "");