#c #templates #c 14 #sfinae
#c #шаблоны #c 14 #sfinae
Вопрос:
В следующем коде, в чем разница между следующими двумя строками шаблона.
> 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>>
Обе вышеуказанные строки работают нормально, я просто хотел узнать преимущества / недостатки использования одного над другим.
#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);
}
Ответ №1:
Они оба работают нормально, если вы пишете одну функцию.
Но если вам нужны две альтернативные функции, этот способ
template <typename T, typename = std::enable_if_t<true == std::is_integral_v<T>>>
void foo (T const amp;)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename = std::enable_if_t<false == std::is_integral_v<T>>>
void foo (T const amp;)
{ std::cout << "isn't integral" << std::endl; }
вы получаете ошибку компиляции, когда таким образом
template <typename T, std::enable_if_t<true == std::is_integral_v<T>, int> = 0>
void foo (T const amp;)
{ 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 amp;)
{ std::cout << "isn't integral" << std::endl; }
работает.
Причина?
Считайте, что вы играете с SFINAE, то есть ошибка замены не является ошибкой.
Суть в подстановке.
Первый способ, когда вы вызываете
foo(0)
замена приводит к
template <typename T, typename = void>
void foo (T const amp;)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename>
void foo (T const amp;)
{ std::cout << "isn't integral" << std::endl; }
то есть… у вас есть две функции с одинаковыми сигнатурами (аргумент шаблона по умолчанию не изменяет сигнатуру функции) и коллизия, вызывающая ее.
Во втором случае у вас есть только
template <typename T, int = 0>
void foo (T const amp;)
{ std::cout << "is integral" << std::endl; }
поскольку ошибка замены во второй функции делает функцию непригодной для использования, и она отбрасывается. Таким образом, у вас есть только доступная функция и нет коллизии.
Комментарии:
1. Четкое объяснение