Building a compile time list incrementally in C++

后端 未结 3 1791
灰色年华
灰色年华 2021-01-06 10:30

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)         


        
3条回答
  •  情话喂你
    2021-01-06 10:59

    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 > > >
    

提交回复
热议问题