Reputation: 357
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
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
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:
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()
avoid using namespace std;
, or is really more probable a name collision (calling sort()
, is called your sort()
or std::sort()
?)
Upvotes: 0
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