Karlos
Karlos

Reputation: 357

Function that only accepts enumeration types

Man, I can't stand this damn templates no mo'

So suppose I have this function...

void sort(vector<int>& vec)
{
    // stuff
}

How can I make that function accept vectors of all enumeration types without overloading it 10 goddamn times?

I don't know much about templates but was thinking about doing something like this... (which gave me the error: type name is not allowed)

template<typename T, std::enable_if_t<std::is_enum<T>>>
void sort(vector<T>& vec)
{
    // stuff
}

Upvotes: 0

Views: 192

Answers (3)

dev_null
dev_null

Reputation: 1997

Just if you use fresh C++ (what I recommend if possible). There is a working example using concepts (c++20). Just tested at gcc 10

#include <type_traits>
#include <vector>
#include <concepts>

template<typename T> requires std::is_enum<T>::value
void sort(std::vector<T> & vec)
{
        // stuff
}

int main()
{
        enum Mew
        {
            neat,
            ugly
        };

        std::vector<Mew> v;
        sort(v);               //works

        std::vector<int> v_int;
        sort(v_int);           //error here

        return 0;
}

Upvotes: 2

max66
max66

Reputation: 66200

First of all: you have to use the value of std::is_enum<T>, not the class itself.

Second: take in count that std::enable_if_t<std::is_enum<T>::value> is void when T is an enum.

So, when T is an enum your function become

// ..................VVVV  void what ?
template<typename T, void>
void sort(vector<T>& vec)
{
    // stuff
}

A possible solution could be add a typename on the left

template<typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

Works, but there is a drawback: if you have to enable/disable only one version of sort(), all goes well. But if you want two different sort() functions (say one for enums and one for not-enums)

template<typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

template<typename T, typename = std::enable_if_t<not std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

This doesn't works because you can't have two functions with the same signature (a default template type/value doesn't change the signature) and the SFINAE failure, removing only the default type for the second argument, doesn't disable the function but only doesn't permit that it match without expressing the second template parameter.

Solution for this problem: let SFINAE works on the left of the equal sign as follows

template<typename T,
         std::enable_if_t<std::is_enum<T>::value, std::nullptr_t> = nullptr>
void sort(vector<T>& vec)
{
    // stuff
}

template<typename T,
         std::enable_if_t<not std::is_enum<T>::value, std::nullptr_t> = nullptr>
void sort(vector<T>& vec)
{
    // stuff
}

This way SFINAE enable/disable the functions so the two alternative function can works without interfere each others.

Another way (compatible with two alternative functions) is to use SFINAE to enable/disable the returned type, so

template<typename T>
std::enable_if_t<std::is_enum<T>::value> sort(vector<T>& vec)
{
    // stuff
}

template<typename T>
std::enable_if_t<not std::is_enum<T>::value> sort(vector<T>& vec)
{
    // stuff
}

A couple of additional not requested suggestions:

  1. doesn't name your classes and functions as classes/functions in the standard library; so give a different name to your sort() to avoid a collision with the standard std::sort()

  2. avoid using namespace std;, or is really more probable a name collision (calling sort(), is called your sort() or std::sort() ?)

Upvotes: 0

Sam Varshavchik
Sam Varshavchik

Reputation: 118340

You were very close:

#include <vector>
    
template<typename T, typename =std::enable_if_t<std::is_enum<T>::value>>
void sort(std::vector<T>& vec)
{
    // stuff
}
enum x {};

void foo()
{
    std::vector<x> X;
    std::vector<int> Y;

    sort(X); // Works
    sort(Y); // ERROR
}

And with C++17 you can save a little bit of typing:

template<typename T, typename =std::enable_if_t<std::is_enum_v<T>>>
void sort(std::vector<T>& vec)
{
    // stuff
}

Upvotes: 0

Related Questions