如何部分专门化枚举值的类模板?

时间:2019-06-18 08:49:08

标签: c++ c++11 templates sfinae template-specialization

可以基于枚举值对模板进行专门化

#include <type_traits>

template<typename T, typename = void>
struct Specialize
{
};

template<typename T>
struct Specialize<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
    void convert() { }
};

enum E
{
};

int main()
{
    Specialize<E> spec;
    spec.convert();
}

// My doubt: is below code valid? if not how to achieve this?

enum E
{
    E1,
    E2
};

int main()
{
    Specialize<E, E1> spec;
    spec.convert();
}

这是对以下问题的回答的后续问题。

How can I partially specialize a class template for ALL enums?

我已将答案中的代码粘贴到上面链接的问题中。

我的更改遇到以下错误。

error: type/value mismatch at argument 2 in template parameter list for _template<class T, class>

2 个答案:

答案 0 :(得分:4)

  

//我的疑问:下面的代码有效吗?

     

Specialize<E, E1> spec;

简短回答:否

长答案。

您已将Specialized定义为模板struct,可以接收两种类型模板参数

template<typename T, typename = void>
struct Specialize
{
};

E是一种类型,而E1

  

如果不能实现这一目标?

如果您希望struct / class接收类型和该类型的值作为模板参数,从而使struct / class的专业化成为可能如果类型是枚举(当且仅当)时,您必须添加typename = void作为第三个模板参数

template<typename T, T Val, typename = void>
struct Specialize
{
};

template<typename T, T Val>
struct Specialize<T, Val, typename std::enable_if<std::is_enum<T>::value>::type>
{
    void convert() { }
};

从C ++ 17开始,您还可以使用auto作为模板值的类型并删除第一个模板参数

template<auto Val, typename = void>
struct Specialize
{
};

template<auto Val>
struct Specialize<Val, std::enable_if_t<std::is_enum_v<decltype(Val)>>>
{
    void convert() { }
};

-编辑-

OP询问

  

我们如何在struct / class之外定义函数“转换”?

不幸的是,在这种情况下,我找不到避免std::enable_if重复的方法

template <typename T, T Val>
struct Specialize<T, Val,
   typename std::enable_if<std::is_enum<T>::value>::type>
 { void convert(); };

template <typename T, T Val>
void Specialize<T, Val,
   typename std::enable_if<std::is_enum<T>::value>::type>::convert ()
 { };

答案 1 :(得分:2)

您的编译器告诉您Specialize<E, E1> spec;无效。

您可以使用std::integral_constant将值包装为类型。

template<typename T, T V>
struct Specialize<std::integral_constant<T, V>, typename std::enable_if<std::is_enum<T>::value>::type>
{
    void convert() { }
};

int main()
{
    Specialize<std::integral_constant<E, E1>> spec;
    spec.convert();
}