你的代码有问题。
排名不分先后
1) 不是错误(我想)但是...使用 typename std::enable_if<...>::type 或者,从 C++14 开始,std::enable_if_t<...>;无需在std::enable_if_t 之前使用typename
2)如果要在参数类型列表中使用std::enable_if,这个不行
template <typename T, std::enable_if_t<(test with T)>>
因为,如果T 的测试为真,则变为
template <typename T, void>
作为模板函数的签名没有意义。
您可以 SFINAE 启用/禁用返回值(请参阅 Igor 或 Marek R 的答案),或者您可以改为编写
template <typename T, std::enable_if_t<(test with T)> * = nullptr>
变成了
template <typename T, void * = nullptr>
有意义,作为签名,有效
3) 在 cmets 中指出,您应该使用 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() 发生冲突,因为在算术值的情况下,两个版本都匹配并且编译器无法选择一个。
我可以提出两种解决方案
(a) 通过 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,比通用版本更受欢迎(启用时);否则使用通用版本。
以下是基于 (b) 解决方案的完整 C++14 示例
#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");
}