Consider the following example.
#include <type_traits>
#include <iostream>
using namespace std;
template <typename T_>
using Integral = typename std::enable_if<std::is_integral<T_>::value,T_>::type;
template <typename T_>
using NotIntegral = typename std::enable_if<!std::is_integral<T_>::value, T_>::type;
template <typename T_>
void printIt(const Integral<T_> &value) { cout << "Integral == " << value << endl; }
template <typename T_>
void printIt(const NotIntegral<T_> &value) { cout << "Non Integral == " << value << endl; }
template <typename T_>
void foo(const T_ &value) { printIt<T_>(value); }
int main(int argc, char** argv)
{
printIt<int>(66); //Must explicitly provide argument type.
//printIt(33); //Compiler error. No overloaded function....????
foo(29.);
return 0;
}
Why do I need to explicitly set the type of template parameter? Should the compiler figure out it's an int
type argument?
Why do I need to explicitly set the type of template parameter?
Because these are non-deduced contexts.
Imagine specializing std::enable_if<std::is_integral<T_>::value,T_>
so that ::type
evaluates to something else. The compiler cannot know the mapping from typename something<T>::type
to T
.
You can achieve your desired result by placing std::enable_if
as part of the return type, so that non-matching overloads are SFINAEd out:
template <typename T>
auto printIt(T x) -> std::enable_if_t<std::is_integral_v<T>, void> { /*...*/ }
template <typename T>
auto printIt(T x) -> std::enable_if_t<!std::is_integral_v<T>, void> { /*...*/ }
live wandbox example
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