vinodkri
vinodkri

Reputation: 33

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

can templates be specialized based on enum values

#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();
}

This is a follow-up question to the answer to the below question.

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

I have copy pasted the code from the answer to the question linked above.

I am getting the following error with my changes.

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

Upvotes: 2

Views: 425

Answers (2)

max66
max66

Reputation: 66230

// My doubt: is below code valid?

Specialize<E, E1> spec;

Short answer: No.

Long answer.

You have defined Specialized as a template struct receiving two types template parameters

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

E is a type but E1 is a value.

if not how to achieve this?

If you want that your struct/class receive, as template parameters, a type and a value of that type, enabling the specialization of the struct/class iff (if and only if) the type is an enum, you have to add the typename = void as third template parameter

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

Starting from C++17 you can also use auto as type for the template value and remove the first template parameter

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

-- EDIT --

The OP asks

how would we define the function "convert" outside the struct/class?

Unfortunately I don't see a way, in this case, to avoid the std::enable_if repetition

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

Upvotes: 4

Caleth
Caleth

Reputation: 63402

Your compiler tells you that Specialize<E, E1> spec; is invalid.

You can use std::integral_constant to wrap a value in a type.

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

Upvotes: 2

Related Questions