Search code examples
c++templatesc++17strong-typingtemplate-argument-deduction

template argument deduction with strongly-typed enumerations


If I have a normal (weak) enumeration, I can use its enumerated values as non-type template parameters, like so:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

and call it as: magic<Cat>(t)

as far as I can see, if I have a strongly-typed enumeration and don't want to hard-code the enumeration type, I end up with:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}

and now I have to write: magic<Animal, Animal::Cat>(t), which seems redundant.

Is there any way to avoid typing out both the enum class and the value, short of

#define MAGIC(E, T) (magic<decltype(E), E>(T));

Solution

  • You can do it like this, if you can use C++17

    #include <type_traits>
    
    enum class Animal { Cat, Dog, Horse };
    
    template <typename EnumClass, EnumClass EnumVal> 
    void magic_impl()
    {
        static_assert(std::is_same_v<EnumClass, Animal>);
        static_assert(EnumVal == Animal::Cat);
    }
    
    template <auto EnumVal>
    void magic()
    {
        magic_impl<decltype(EnumVal), EnumVal>();
    }
    
    int main()
    {
        magic<Animal::Cat>();
    }
    

    demo: http://coliru.stacked-crooked.com/a/9ac5095e8434c9da