В вашем коде есть некоторые проблемы.
Ни в каком конкретном порядке
1) не ошибка (я полагаю), но ... используйте typename std::enable_if<...>::type
или, начиная с C ++14, std::enable_if_t<...>
;нет необходимости использовать typename
до std::enable_if_t
2), если вы хотите использовать std::enable_if
в списке типов параметров, этот не работает
template <typename T, std::enable_if_t<(test with T)>>
, потому что, если проверка с T
верна, становитесь
template <typename T, void>
, который не имеет смысла в качестве подписи для функции шаблона.
Вы можете включить / отключить возвращаемое значение SFINAE (см. ответы Игоря или Марека R) или вы можете написать вместо этого
template <typename T, std::enable_if_t<(test with T)> * = nullptr>
, которые становятся
template <typename T, void * = nullptr>
и имеют смысл, как подпись, и работают
3) как указано в комментариях, вы должны использовать std::remove_reference
, поэтому
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type)
теперь эта функция должна перехватывать арифметические значения, но ...
4) предшествующее processImpl()
,для арифметических значений столкнитесь с другими processImpl()
, поскольку в случае арифметических значений обе версии совпадают, и компилятор не может выбирать одно из другого.
Я могу предложить два решения
(а) отключить через SFINAE вторую версию в арифметических случаях;Я имею в виду, напишите второй следующим образом:
template <typename Type,
std::enable_if_t<false == std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type)
(b) пройти через промежуточную функцию, которая отправляет дополнительное значение int
и получает int
в арифметической версии и long
вуниверсальный;Я имею в виду что-то вроде
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type, int)
{ /* ... */ }
template <typename Type>
ArchiveType & processImpl (Type && type, long)
{ /* ... */ }
template <typename Type>
ArchiveType & processImpl (Type && type)
{ return processImpl(type, 0); }
Таким образом, арифметическая версия, получающая ровно int
, предпочтительнее (если она включена), чем универсальная версия;в противном случае используется универсальная версия.
Ниже приводится полный рабочий пример C ++ 14, основанный на решении (b)
#include <iostream>
#include <type_traits>
template <typename ArchiveType>
struct OutputArchive
{
ArchiveType value {};
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type, int)
{
std::cout << "--- processImpl aritmetic: " << type << std::endl;
return value;
}
template <typename Type>
ArchiveType & processImpl (Type && type, long)
{
std::cout << "--- processImpl generic: " << type << std::endl;
return value;
}
template <typename Type>
ArchiveType & processImpl (Type && type)
{ return processImpl(type, 0); }
};
int main()
{
OutputArchive<int> oa;
long l{2l};
oa.processImpl(l);
oa.processImpl(3);
oa.processImpl("abc");
}