Yes, SFINAE can be applied to non-type template parameters as well, such as integers, enums, or pointers.
For example, let's say we want to write a ToString
function that converts an integral value to a string, but we only want to enable it for unsigned integral types. We can achieve this using SFINAE on a non-type template parameter:
#include <type_traits>
#include <string>
using std::enable_if_t, std::is_unsigned_v;
template<typename T,
enable_if_t<is_unsigned_v<T>, int> = 0
>
std::string ToString(T value) {
return std::to_string(value);
}
Here, the second template parameter is an unused non-type parameter of type int
. The std::enable_if
condition checks if T
is an unsigned type using the std::is_unsigned
type trait.
If T
is unsigned, the second parameter will have a type of int
and the template will be viable. If T
is not unsigned, a substitution failure occurs, removing this template from the overload set.
We can test it like this:
#include <type_traits>
#include <string>
using std::enable_if_t, std::is_unsigned_v;
template<typename T,
enable_if_t<is_unsigned_v<T>, int> = 0
>
std::string ToString(T value) {
return std::to_string(value);
}
int main() {
unsigned int x = 42;
int y = -10;
// OK
std::string sx = ToString(x);
// Substitution failure, int is not unsigned
std::string sy = ToString(y);
}
So SFINAE works consistently with both type and non-type template parameters. The key is to introduce an unused parameter whose validity depends on the properties you want to constrain.
Answers to questions are automatically generated and may not have been reviewed.
Learn how SFINAE allows templates to remove themselves from overload resolution based on their arguments, and apply it in practical examples.