Я пытаюсь понять, как использовать C ++ (11) <type_traits>
,
Вот моя тривиальная тестовая программа
#include <type_traits>
template<class U, class S>
inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a,
typename std::enable_if<std::is_signed <S>::value,S>::type b)
{
return a + b;
}
int main(int argc, const char * argv[], const char * envp[])
{
unsigned int ui;
int i;
auto a = add(ui, i);
return 0;
}
При компиляции с GCC 4.8.1 это ошибки как
/home/per/f.cpp: In function ‘int main(int, const char**, const char**)’:
/home/per/f.cpp:15:23: error: no matching function for call to ‘add(unsigned int&, int&)’
auto a = add(ui, i);
^
/home/per/f.cpp:15:23: note: candidate is:
/home/per/f.cpp:5:10: note: template<class U, class S> U add(typename std::enable_if<std::is_unsigned<U>::value, U>::type, typename std::enable_if<std::is_signed<S>::value, S>::type)
inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a,
^
/home/per/f.cpp:5:10: note: template argument deduction/substitution failed:
/home/per/f.cpp:15:23: note: couldn't deduce template parameter ‘U’
auto a = add(ui, i);
^
Я понятия не имею, почему GCC не может определить параметр шаблона U
, Кто-нибудь знает, какая информация отсутствует в моем коде, то есть как я пишу программу на C ++ 11, которая принимает целочисленный тип без знака в качестве первого аргумента и целочисленный тип со знаком в качестве второго?
typename std::enable_if<std::is_unsigned<U>::value,U>::type
не выводимый контекст. Для того, чтобы вывести U
Исходя из этого, компилятору потребуется возможность применить обратную операцию std::enable_if
, Это не выглядит слишком сложно, это правда, но это потому, что вы говорите о такой простой вещи, как enable_if
, Было бы невозможно требовать этого для каждой черты, поэтому C ++ просто играет круто и не делает никаких странных исключений из правил: это вообще не выводимо, в этом не выводимо.
Вы можете сделать это следующим образом:
template<class U, class S,
EnableIf<std::is_unsigned<U>, std::is_signed<S>>...>
// see http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html
U add(U a, S b)
Или в компиляторах, которые не поддерживают этот стиль должным образом, вы можете просто добавить дополнительный аргумент по умолчанию:
template<class U, class S>
U add(U a, S b,
typename std::enable_if<std::is_unsigned<U>::value
&& std::is_signed<S>::value,void>::type* = nullptr)
… или возиться с типом возврата.
template<class U, class S>
typename std::enable_if<std::is_unsigned<U>::value
&& std::is_signed<S>::value,U>::type
add(U a, S b)
Вы не даете компилятору шанс вывести U
а также S
, Вы можете переписать свою функцию следующим образом и переместить проверки SFINAE в список параметров шаблона:
template<class U, class S,
typename std::enable_if<std::is_unsigned<U>::value &&
std::is_signed <S>::value
>::type* = nullptr>
inline U add(U a, S b)
{
return a + b;
}
Вот живой пример.
Сначала вы должны определить типы до Вы можете рассуждать о типах!
Так должно быть:
template <typename U, typename S>
typename std::enable_if<std::is_unsigned<U>::value &&
std::is_signed<S>::value>, U>::type
add(U u, S s)
{
// ...
}
Невозможно вывести параметр шаблона из выражения «вложенный typedef». То есть можно вывести U
от some_template<U>
, но не из some_template<U>::type
,
Компилятор не может перечислять все (бесконечные!) Экземпляры some_template
и посмотрите, для какого из них вложенная typedef равна фактическому типу аргумента.
Пытаться:
template<class U, class S>
typename std::enable_if<std::is_unsigned<U>::value && std::is_signed<S>,U>::type
add(U a , S b)
{
return a + b;
}