我正在尝试实现一个OutputArchive模板类,它有一个模板函数processImpl()。看起来是这样的:
template<typename ArchiveType>
class OutputArchive {
...
template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>>> inline
ArchiveType& processImpl(Type&& type) {
// Implementation
}
template<typename Type, typename = void> inline
ArchiveType& processImpl(Type&& type) {
// Implementation
}
}这里的想法是,如果我将一个char、int、float等传递给我的processImpl()函数,那么应该使用第一个重载;但是,情况并非如此。第二个过载似乎总是被使用,我完全不知道我可能做错了什么。我想这确实与我使用std::enable_if的方式有关
发布于 2018-10-13 22:33:47
因此,为了使它工作,您应该使用std::enable_if的2种情况。我将给出一个返回类型的示例,但是使用模板参数也可以。
template<typename Type> inline
typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
// Implementation
}
template<typename Type> inline
typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
// Implementation
}注意第二种情况下的否定。
但是对于C++17来说,一个更好的方法是使用constexpr:
ArchiveType& processImpl(Type&& type) {
if constexpr(std::is_arithmetic_v<type>) {
// implementation
} else {
// implementation
}
}发布于 2018-10-13 22:55:52
您的代码中有一些问题。
没有特别的顺序
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>作为模板函数的签名,这是没有意义的。
您可以启用/禁用返回值(请参阅Igor或Marek 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()发生冲突,因为在算术值的情况下,两个版本和编译器都不能选择一个而另一个。
我可以提出两种解决方案
(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");
}发布于 2018-10-13 22:41:45
这应该能起作用
template<typename ArchiveType>
class OutputArchive {
...
template<typename Type>
inline
typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&>
processImpl(Type type) {
// Implementation
}
template<typename Type>
inline
typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&>
processImpl(Type&& type) {
// Implementation
}
};活样品。
https://stackoverflow.com/questions/52797598
复制相似问题