简体   繁体   中英

Difference between two template code patterns where in one case a number is assigned whereas in the other the keyword typename is used

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM