'Template Function Specialization for Integer Types
Suppose I have a template function:
template<typename T>
void f(T t)
{
...
}
and I want to write a specialization for all primitive integer types. What is the best way to do this?
What I mean is:
template<typename I where is_integral<I>::value is true>
void f(I i)
{
...
}
and the compiler selects the second version for integer types, and the first version for everything else?
Solution 1:[1]
I would use overload resolution. That spares you from having to use the gross SFINAE hack. Unfortunately there are many areas where you can't avoid it, but this fortunately isn't one of those.
template<typename T>
void f(T t)
{
f(t, std::is_integral<T>());
}
template<typename T>
void f(T t, std::true_type)
{
// ...
}
template<typename T>
void f(T t, std::false_type)
{
// ...
}
Solution 2:[2]
Using c++11, std::enable_if ( http://en.cppreference.com/w/cpp/types/enable_if ) can be used to do that:
template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
void f(T t) {...}
Solution 3:[3]
You can use a helper template that you can specialize like this:
#include <string>
#include <iostream>
#include <type_traits>
template <typename T, bool = std::is_integral<T>::value>
struct Foo {
static void bar(const T& t) { std::cout << "generic: " << t << "\n"; }
};
template <typename T>
struct Foo<T, true> {
static void bar(const T& t) { std::cout << "integral: " << t << "\n"; }
};
template <typename T>
static void bar(const T& t) {
return Foo<T>::bar(t);
}
int main() {
std::string s = "string";
bar(s);
int i = 42;
bar(i);
return 0;
}
output:
generic: string
integral: 42
Solution 4:[4]
Here is C++20 solution
template<std::integral T>
void f(T v) {
...
}
I think It's actually overloaded function but works the same.
Solution 5:[5]
What about a more straightforward and better readable way by just implementing the different versions inside the function body?
template<typename T>
void DoSomething(T inVal) {
static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value, "Only defined for float or integral types");
if constexpr(std::is_floating_point<T>::value) {
// Do something with a float
} else if constexpr(std::is_integral<T>::value) {
// Do something with an integral
}
}
You dont have to worry about performance. The conditions are compile time constant and a descent compiler will optimize them away. "if constexpr" is c++17 unfortunately but you may remove "constexpr" when both versions compile without errors for both types
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Johannes Schaub - litb |
| Solution 2 | |
| Solution 3 | mitchnull |
| Solution 4 | |
| Solution 5 |
