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)
In OP's own solution, it only works for global scope, not class scope, nor function scope. My implementation here works for all of global, class and function scope. Another advantage over OP's solution is my solution allow multiple list START_LIST/END_LIST pairs overlap, i.e. different list constructions can be interleaving.
One small limitation is it uses __COUNTER__
macro, which is not part of starndard, but it is well supported by gcc, clang and MSVC, so portability is not a big issue here. Another thing is for function scope, it has to use a separate macro START_LIST_FUNC
and ADD_TO_LIST_FUNC
as I make use function overload resolution but in function scope it can't declare static
function, while at class level it has to use static
function.
EDIT: incorporate the idea of ListReverseHelper from OP's comment to make it much simpler.
#include
#include
using namespace std;
struct Nil {};
template struct Cons {};
template struct ListReverseHelper;
template
struct ListReverseHelper {
using Type = Reversed;
};
template
struct ListReverseHelper, Reversed> {
using Type = typename ListReverseHelper>::Type;
};
template struct ListMakerKey : ListMakerKey {};
template struct ListMakerKey {};
#define START_LIST_(name, modifier) \
struct name##_ListMaker {}; \
modifier Nil list_maker_helper_(ListMakerKey);
#define ADD_TO_LIST_(name, type, modifier) \
modifier Cons{}))> \
list_maker_helper_(ListMakerKey);
#define END_LIST(name) \
using name = typename ListReverseHelper{})), Nil>::Type;
#define START_LIST(name) START_LIST_(name, static)
#define ADD_TO_LIST(name, type) ADD_TO_LIST_(name, type, static)
#define START_LIST_FUNC(name) START_LIST_(name,)
#define ADD_TO_LIST_FUNC(name, type) ADD_TO_LIST_(name, type,)
START_LIST(List)
ADD_TO_LIST(List, int)
int a = 10;
ADD_TO_LIST(List, float)
int b = 10;
START_LIST(List2)
ADD_TO_LIST(List, int)
int c = 10;
ADD_TO_LIST(List2, float)
ADD_TO_LIST(List, double)
ADD_TO_LIST(List2, int)
ADD_TO_LIST(List2, float)
END_LIST(List2)
ADD_TO_LIST(List, double)
ADD_TO_LIST(List, char)
END_LIST(List)
struct A {
START_LIST(List3)
ADD_TO_LIST(List3, int)
int a = 10;
ADD_TO_LIST(List3, float)
int b = 10;
ADD_TO_LIST(List3, double)
ADD_TO_LIST(List3, int)
END_LIST(List3)
};
int main() {
START_LIST_FUNC(List4)
ADD_TO_LIST_FUNC(List4, char)
int a = 10;
ADD_TO_LIST_FUNC(List4, float)
int b = 10;
ADD_TO_LIST_FUNC(List4, int)
ADD_TO_LIST_FUNC(List4, char)
END_LIST(List4)
List x;
List2 y;
A::List3 z;
List4 w;
cout << typeid(x).name() << endl;
cout << typeid(y).name() << endl;
cout << typeid(z).name() << endl;
cout << typeid(w).name() << endl;
}
Compiled under g++-4.8:
[hidden]$ g++ -std=c++11 x.cpp && c++filt -t `./a.out`
Cons > > > > >
Cons > >
Cons > > >
Cons > > >