I have a simple function:
template<class T>
typename std::enable_if_t<std::is_arithmetic_v<T>>
foo(T val) { }
I would like also to have another function with the same name:
template<class T>
void foo(T value) { }
I want to call the first function with arithmetic types and the second function for all other types. An idea I have is to change the second function into this:
template<class T>
typename std::enable_if_t<!std::is_arithmetic_v<T>>
foo(T val) { }
but is there a better way to achieve that?
CodePudding user response:
A better and more intuitive way is to use C 20 concepts.
#include <concepts>
template<class T>
requires std::is_arithmetic_v<T>
void foo(T value) { }
template<class T>
void foo(T value) { }
When you call foo(0)
, since the constraint of the first overload is satisfied, it will take precedence over the second unconstrainted overload.
When you call foo("hello")
, since the constraint of the first overload is not satisfied, the compiler will select the second overload.
CodePudding user response:
Use if constexpr
:
template<class T>
void foo(T value)
{
if constexpr (std::is_arithmetic_v<T>) {
// ... one implementation
} else {
// ... another implementation
}
}
CodePudding user response:
You can do it by leverage overload resolution:
template<class T>
typename std::enable_if_t<std::is_arithmetic_v<T>>
foo(T val, int)
{
std::cout << "arithmetic: " << (val val) << '\n';
}
template<typename T>
void foo(const T& val, long)
{
std::cout << "Def: " << val << '\n';
}
template<typename T>
void foo(T&& x)
{
foo(std::forward<T>(x), 0);
}
https://godbolt.org/z/sM1KbT8vE
now int
overload is preferred, but if it fails because of SFINAE it jumps to long
overload.
In simple case I prefer !std::eneble_if_t
approach, but if you have more special cases overload resolution is more handy.