Building a compile time list incrementally in C++

后端 未结 3 1775
灰色年华
灰色年华 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 11:18

    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, "");
    

提交回复
热议问题