Applying SFINAE to Non-Type Template Parameters
Can I use SFINAE with non-type template parameters, like integers?
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.
Using SFINAE to Control Overload Resolution
Learn how SFINAE allows templates to remove themselves from overload resolution based on their arguments, and apply it in practical examples.