In the following code, what is the difference between the following two template lines.
> 1. template<class T, std::enable_if_t<std::is_integral<T>::value, int> = 0> > 2. template<class T, typename = std::enable_if_t<std::is_integral<T>::value>>
Both the above lines are working fine, I just wanted to know the advantages/disadvantage in using one over the other.
#include <type_traits>
#include <iostream>
template<class T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
//template<class T, typename = std::enable_if_t<std::is_integral<T>::value>>
int onlyOnInt(T a, T b)
{
return a+b;
}
int main()
{
onlyOnInt(1, 2);
}
They are both working fine, if you write a single function.
But when you want two alternative functions, this way
template <typename T, typename = std::enable_if_t<true == std::is_integral_v<T>>>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename = std::enable_if_t<false == std::is_integral_v<T>>>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
you get a compilation error where this way
template <typename T, std::enable_if_t<true == std::is_integral_v<T>, int> = 0>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, std::enable_if_t<false == std::is_integral_v<T>, int> = 0>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
works.
The reason?
Consider you're playing with SFINAE, that is Substitution Failure Is Not An Error.
The point is Substitution.
The first way, when you call
foo(0)
the substitution bring to
template <typename T, typename = void>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
that is... you have two functions with the same signatures (a default template argument doesn't change the signature of a function) and a collision calling it.
In the second way you have only
template <typename T, int = 0>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
because the substitution failure in the second function make the function unusable and it's discarded. So you have only a function available and no collision.