Home > Mobile >  Partial Template Specialization using enable_if
Partial Template Specialization using enable_if

Time:02-27

I am trying to understand how to use type traits with std::enable_if to "enable" partial specializations of a class. Here is the example code I am attempting to get workingL

#include <type_traits>
#include <iostream>

class AbstractFoo {
public:
    virtual const char* name() const = 0;
};

template <typename T, typename Enable = void>
class Foo;

template <>
class Foo<int> : public AbstractFoo{
public:
    const char* name() const override { return "int"; }
};

template <>
class Foo<char> : public AbstractFoo {
public:
    const char* name() const override { return "char"; }
};

template <typename T>
class Foo<T, typename std::enable_if<std::is_enum<T>::value, T>::type> : public AbstractFoo {
public:
    const char* name() const override { return "enum"; }
};

enum class MyEnum {
    VAL1,
    VAL2,
    VAL3
};

int main() {
    Foo<int> v1;
    Foo<char> v2;
    Foo<MyEnum> v3;
    
    std::cout << "v1.name()=" << v1.name() << std::endl;
    std::cout << "v2.name()=" << v2.name() << std::endl;
    std::cout << "v3.name()=" << v3.name() << std::endl;

    return 0;
};

My goal is to have specific specializations for certain types (e.g., int and char), but, if the type is an enum, to use my partial specialization. However, when I attempt to compile this code, I get the following error

error: aggregate 'Foo v3' has incomplete type and cannot be defined

Which I assume means my specialization was not chosen and thus never becomes defined. What am I doing wrong?

CodePudding user response:

In the declaration of Foo the second template parameter defaults to void. That means that the following variable:

Foo<MyEnum> v3;

is actually

Foo<MyEnum, void> v3;

Now the question is: does this correspond to the specialization you want? Not really, because in your specialization for enum:

  • std::is_enum<T>::value = true when T = MyEnum
  • std::enable_if<std::is_enum<T>::value, T>::type = T = MyEnum when T=MyEnum

So, for T=MyEnum, your give the specialization for Foo<T, T>, which does not match the variable above.

As noted in a comment, a simple fix is to declare the specialization as

class Foo<T, typename std::enable_if<std::is_enum<T>::value>::type>

In this way, the second template parameter is void when T=MyEnum, so it matches the variable declaration of v3.

  • Related