Tag dispatch takes advantage of overload resolution to select the right overload.
auto f_impl(std::true_type) { return true; }
auto f_impl(std::false_type) { return std::string("No"); }
template <class T>
auto f(const T& t) {
return f_impl(std::is_integral<T>());
}
SFINAE disables a candidate by making it ineligible due to substitution failure.
Substitution failure is just what it says on the tin: Trying to substitute concrete arguments for the template parameters and encountering an error, which in the immediate context only rejects that candidate.
template <class T>
auto f(const T& t)
-> std::enable_if_t<std::is_integral_v<T>, bool> {
return true;
}
template <class T>
auto f(const T& t)
-> std::enable_if_t<!std::is_integral_v<T>, std::string> {
return std::string("No");
}
Sometimes, one or the other technique is easier to apply. And naturally they can be combined to great effect.
Complementary techniques are partial and full specialization. Also, if constexpr
can often simplify things.