Home Templating Structs to Combine Enums
Reply: 2

Templating Structs to Combine Enums

Nicholas Mulianto
1#
Nicholas Mulianto Published in 2018-02-14 03:52:25Z

I am currently doing a project that requires me to aggregate multiple enums to one huge enum. I could just write it, but managing one would be troublesome. I have an idea of using structs to wrap around the different enums and templating, the parameter would be an integer, for example:

template <int START>
struct first_enum
{
    enum constant
    {
        a = START, 
        b, c, d
    };

    static constexpr int end() { return d; }
}

template <int START>
struct second_enum
{
    enum constant
    {
        e = START, 
        f
    };

    static constexpr int end() { return f; }
}

template <int START>
struct third_enum
{
    enum constant
    {
        g = START, 
        h
    };

    static constexpr int end() { return h; }
}

Then I have another struct that inherits from the previous structs:

struct enum_all : public first_enum<0>,
                         second_enum<first_enum<0>::end() + 1>,
                         third_enum<second_enum<first_enum<0>::end() + 1>::end() + 1> {};

This way enum_all will have members a, b, c, ..., h with values ranging from 0...7.

However writing that down is very cumbersome and not scalable (imagine adding more structs).

I suspect you could do this using variadic templates, however I am still a beginner with template metaprogramming. Here is what I currently have for a base case and it compiles.

template <int START, template<int> typename ENUM>
struct enum_all_t : public ENUM<START>
{

};

Calling enum_all_t<0, first_enum>::a gives me the correct result. I tried adding another template specialization, but it tells me "error: redeclared with 3 template parameters".

template <int START, template <int> typename ENUM, template <int> typename... ENUMS>
struct enum_all_t : public ENUM<START>, enum_all_t<ENUM<START>::end() + 1, ENUMS> {};
Denis Sheremet
2#
Denis Sheremet Reply to 2018-02-14 04:12:28Z

Try to add end-of-recursion explicit declaration after your declaration. This should work:

template <int START, template <int> typename ENUM, template <int> typename... ENUMS>
struct enum_all_t : public ENUM<START>, enum_all_t<ENUM<START>::end() + 1, ENUMS...> {};

template <int START, template <int> typename ENUM>
struct enum_all_t<START, ENUM> : public ENUM<START> {};

The idea is what you have to accept the same amount of arguments in each of your template specialisation. In your example you define template with 2 args, and then redefine it with 3. In my example I've defined it with 3 args, and then redefined it again with 3 args, but last one empty.

max66
3#
max66 Reply to 2018-02-14 04:28:18Z

I prepared a solution but now I see that is very similar (ground case and recursive case reverted) than the Denis Sheremet's one (+1).

Anyway... I propose a enum_all_helper with the base template as ground case

template <int, template <int> class ...>
struct enum_all_helper
 { };

and a recursive specialization

template <int I, template <int> class E0, template <int> class ... Es>
struct enum_all_helper<I, E0, Es...>
   : public E0<I>, public enum_all_helper<E0<I>::end()+1, Es...>
 { };

So enum_all can be simply written as follows

template <template <int> class ... Es>
struct enum_all : public enum_all_helper<0, Es...>
 { };

The following is a full compiling example

#include <type_traits>

template <int START>
struct first_enum
 {
    enum constant { a = START, b, c, d };

    static constexpr int end() { return d; }
 };

template <int START>
struct second_enum
 {
    enum constant { e = START, f };

    static constexpr int end() { return f; }
 };

template <int START>
struct third_enum
 {
    enum constant { g = START, h };

    static constexpr int end() { return h; }
 };

template <int, template <int> class ...>
struct enum_all_helper
 { };

template <int I, template <int> class E0, template <int> class ... Es>
struct enum_all_helper<I, E0, Es...>
   : public E0<I>, public enum_all_helper<E0<I>::end()+1, Es...>
 { };

template <template <int> class ... Es>
struct enum_all : public enum_all_helper<0, Es...>
 { };

int main()
 {
   using EA = enum_all<first_enum, second_enum, third_enum>;

   static_assert( std::is_base_of<first_enum<0>, EA>{}, "!" );
   static_assert( std::is_base_of<second_enum<4>, EA>{}, "!" );
   static_assert( std::is_base_of<third_enum<6>, EA>{}, "!" );
 }
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.309362 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO