#include <type_traits>
enum class MyEnum
{
Hello
};
template <typename T, typename Enable = void>
class MyClass
{
public:
MyClass(T obj) : e(obj)
{}
private:
T e;
};
template <typename T>
class MyClass <T,
typename std::enable_if< std::is_enum<T>::value
&& std::is_same<typename std::underlying_type<T>::type,
int>::value>::type >
{
public:
MyClass(T obj) : e(obj)
{}
private:
T e;
};
int main()
{
MyClass<MyEnum> c(MyEnum::Hello);
MyClass<int> c1(1); //does not compile due to std::underlying_type
return 0;
}
I would like to be able to specialize MyClass for enums of underlying type 'int'. I can't do that using std::underlying_type because it is only specific to enums. Any ideas on how I can proceed?
Each enum type has a corresponding integral type called the underlying type of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the enum_base is present, it explicitly declares the underlying type.
The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. Enums are enumerated data type in C#.
The type of a C++ enum is the enum itself. Its range is rather arbitrary, but in practical terms, its underlying type is an int . It is implicitly cast to int wherever it's used, though.
The enum class body can include methods and other fields. The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.
A simple enough solution to this quirk is to insulate std::underlying_type
behind your own SFINAE-friendly trait:
template <class T, class = void>
struct underlying_type {};
template <class T>
struct underlying_type<
T,
typename std::enable_if<std::is_enum<T>::value>::type
> {
using type = typename std::underlying_type<T>::type;
};
Then your specialization can be written as:
template <typename T>
class MyClass<
T,
typename std::enable_if<std::is_same<
typename underlying_type<T>::type,
int
>::value>::type
> {
// ...
};
With one extra (delayed) indirection with conditional<..>::type::type
:
template <typename T> struct Identity { using type = T; };
template <typename E>
class MyClass <E,
typename std::enable_if<
std::is_enum<E>::value
&& std::is_same<
int,
typename std::conditional<
std::is_enum<E>::value,
std::underlying_type<E>,
Identity<E>
>::type::type
>::value
>::type
>
{
// ...
};
We really does std::underlying_type<E>::type
only for enum.
Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With