Suppose we have some SFINAE member function:
class foo{
template <class S, class = std::enable_if_t<std::is_integral<S>::value, S>
void bar(S&& s);
template <class S, class = std::enable_if_t<!std::is_integral<S>::value, S>
void bar(S&& s);
}
If we declared it as above, then how can we define them? Both of their function signatures would look like:
template <class S, class>
inline void foo::bar(S&& s){ ... do something ... }
I have seen examples where one returns an std::enable_if_t<...>
like:
template <class S, class>
auto bar(S&& s) -> std::enable_if_t<!std::is_integral<S>::value, S>(...){
... do something ...
}
To disambiguate based off of the return type. But I don't want to return anything.
since default arguments are not part of a function signature, make them not default
class foo{
template <class S, typename std::enable_if<std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
template <class S, typename std::enable_if<!std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
};
EDIT: by popular demand, Here's the same code in C++17:
class foo{
public:
template <class S>
void bar(S&& s)
{
if constexpr(std::is_integral_v<S>)
std::cout << "is integral\n";
else
std::cout << "NOT integral\n";
}
};
constexpr if statements are special to the compiler because the branch is chosen at compile time, and the non-taken branch isn't even instantiated
C++17 Demo
You can still do this in the return type just fine. Just keep the default of enable_if
(which is void
). Even if you're just on C++11, just add this alias:
template <bool B, typename T=void>
using enable_if_t = typename std::enable_if<B, T>::type;
And then you can do:
template <class S>
enable_if_t<std::is_integral<S>::value>
bar(S);
template <class S>
enable_if_t<!std::is_integral<S>::value>
bar(S);
Or:
template <class S>
auto bar(S) -> enable_if_t<std::is_integral<S>::value>
template <class S>
auto bar(S) -> enable_if_t<!std::is_integral<S>::value>
Either way, you have two properly disambiguated functions that return void
.
With C++11 compiler another option is to use tag dispatching.
template <class S>
void bar(S&& s)
{
bar(std::forward<S>(s), std::is_integral<S>{});
}
template <class S>
void bar(S&& s, std::true_type)
{
...
}
template <class S>
void bar(S&& s, std::false_type)
{
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With