我已经阅读了一些有关SFINAE的文章,但找不到我的案例的解决方案。这就是我想要做的事情:
#include <type_traits>
struct CByteArray {};
struct HLVariant {
HLVariant() {}
HLVariant(const HLVariant&) {}
HLVariant(const CByteArray&) {}
};
template <typename T>
struct Serializer
{
static inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
static_assert(std::is_pod<T>::value, "Not a POD type");
return CByteArray();
}
static inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
return Serializer<HLVariant>::serialize(HLVariant(value));
}
};
template <>
struct Serializer<HLVariant>
{
static inline CByteArray serialize(const HLVariant& value)
{
return CByteArray();
}
};
int main()
{
int i = 0;
Serializer<int>::serialize(i);
Serializer<CByteArray>::serialize(CByteArray());
Serializer<HLVariant>::serialize(HLVariant());
return 0;
}
但是,当然,我得到了error C2039: 'type' : is not a member of 'std::enable_if<false,CByteArray>'
如何实现我的目标?
此外,是否可以以某种方式重新组织Serializer
,以便可以隐式推断模板参数 - Serializer::serialize(i);
而不是Serializer<int>::serialize(i);
?
答案 0 :(得分:3)
要使用std::enable_if<condition>
,您必须处于条件的模板中。一种选择是将您的函数声明为具有默认参数
template <typename T>
struct Serializer
{
template<bool pod = std::is_pod<T>::value> // template over condition
static typename std::enable_if<pod, CByteArray>::type
serialize(const T& value)
{ return CByteArray(); }
template<bool pod = std::is_pod<T>::value>
static typename std::enable_if<!pod, CByteArray>::type
serialize(const T& value)
{ return Serializer<HLVariant>::serialize(HLVariant(value)); }
};
template<>
struct Serializer<HLVariant>
{
static CByteArray serialize(const HLVariant&);
};
或者,您可以直接在类模板的范围内应用SFINAE:
template<typename T, typename = void> struct Serializer;
template<>
struct Serializer<HLVariant>
{
static CByteArray serialize(const HLVariant&)
{ return CByteArray(); }
};
template<typename T>
struct Serializer<T,typename std::enable_if<is_pod<T>::type>
{
static CByteArray serialize(const T&)
{ return CByteArray(); }
};
template<typename T>
struct Serializer<T,typename std::enable_if<!is_pod<T>::type>
{
static CByteArray serialize(const T&value)
{ return Serializer<HLVariant>::serialize(HLVariant(value));
};
或者你可以摆脱类Serializer并通过模板函数直接声明:
inline CByteArray
serialize(const HLVariant&)
{ return CByteArray(); }
template<typename T>
inline typename enable_if<std::is_pod<T>::value, CByteArray>::type
serialize(const T&)
{ return CByteArray(); }
template<typename T>
inline typename enable_if<!std::is_pod<T>::value, CByteArray>::type
serialize(const T&value)
{ return serialize(HLVariant(value)); }
BTW,C ++ 14定义了非常有用的别名
template<bool C, typename T>
using enable_if_t = typename enable_if<C,T>::type;
但你当然可以这样做。这样可以避免繁琐的typename
和::type
。
答案 1 :(得分:3)
SFINAE是&#34;替换失败不是错误的首字母缩写。&#34;根据定义,这意味着它仅在模板参数替换模板定义中的参数时适用。您的serialize
函数是类模板的成员函数,它们本身不是函数模板。直接的答案是将函数转换为函数模板(Live code):
template <typename> struct Serializer;
template <>
struct Serializer<HLVariant>
{
static CByteArray serialize(const HLVariant& /* value */)
{
return CByteArray();
}
};
template <typename T>
struct Serializer
{
template <typename U = T>
static typename std::enable_if<std::is_pod<U>::value, CByteArray>::type
serialize(const U& /* value*/)
{
static_assert(std::is_pod<U>::value, "Not a POD type");
return CByteArray();
}
template <typename U = T>
static typename std::enable_if<!std::is_pod<U>::value, CByteArray>::type
serialize(const U& value)
{
return Serializer<HLVariant>::serialize(HLVariant(value));
}
};
我删除了冗余的inline
,因为类主体中定义的所有函数都是隐式内联的,我重新定位Serializer<HLVariant>
特化以确保在引用之前正确声明它。拥有一个只有静态成员函数的类有点傻了;您可以更合理地将其实现为一组重载函数(Live code):
inline CByteArray serialize(const HLVariant& /* value */)
{
return CByteArray();
}
template <typename T>
inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type
serialize(const T& /* value*/)
{
static_assert(std::is_pod<T>::value, "Not a POD type");
return CByteArray();
}
template <typename T>
inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type
serialize(const T& value)
{
return serialize(HLVariant(value));
}
int main()
{
int i = 0;
serialize(i);
serialize(CByteArray());
serialize(HLVariant());
}
鉴于SFINAE使用阻碍了代码可读性,我更倾向于在此实例中使用标签分派。不是使用SFINAE管理两个函数的重载解析,而是使用第三个函数调用POD或非POD(Yet more live code)的相应实现:
inline CByteArray serialize(const HLVariant& /* value */)
{
return CByteArray();
}
template <typename T>
inline CByteArray serialize(std::true_type, const T& /* value*/)
{
static_assert(std::is_pod<T>::value, "Not a POD type");
return CByteArray();
}
template <typename T>
inline CByteArray serialize(std::false_type, const T& value)
{
return serialize(HLVariant(value));
}
template <typename T>
inline CByteArray serialize(const T& value)
{
return serialize(std::is_pod<T>{}, value);
}
SFINAE功能强大,但又足够危险,可以安全地锁定您可以使用更简单的工具解决的问题。