用于结合枚举的模板结构

时间:2018-02-14 03:52:25

标签: c++ c++11 templates variadic-templates template-meta-programming

我目前正在做一个项目,要求我将多个枚举汇总到一个巨大的枚举。我可以写它,但管理一个会很麻烦。我有一个想法,使用结构包围不同的枚举和模板,参数将是一个整数,例如:

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

然后我有另一个继承自前面结构的结构:

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> {};

这种方式enum_all会有成员abc,...,h,其值介于0 ... 7之间。

然而,写下来是非常麻烦且不可扩展(想象添加更多结构)。

我怀疑你可以使用可变参数模板来做到这一点,但我仍然是模板元编程的初学者。以下是我目前对基础案例的编制和编译。

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

};

致电enum_all_t<0, first_enum>::a会给我正确的结果。我尝试添加另一个模板专门化,但它告诉我&#34;错误:重新声明了3个模板参数&#34;。

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> {};

2 个答案:

答案 0 :(得分:1)

尝试在声明后添加递归结束显式声明。这应该有效:

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> {};

这个想法是你必须在每个模板专业化中接受相同数量的参数。在你的例子中,你用2个args定义模板,然后用3重新定义它。在我的例子中,我用3个args定义它,然后用3个args重新定义它,但最后一个空。

答案 1 :(得分:1)

我准备了一个解决方案,但现在我发现它与Denis Sheremet的一个(+1)非常相似(地面案例和递归案例还原)。

无论如何......我建议enum_all_helper将基本模板作为基础案例

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...>
 { };

所以enum_all可以简单地写成如下

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

以下是完整的编译示例

#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>{}, "!" );
 }