SFINAE is an acronym for "Substitution Failure Is Not An Error." By definition, that means it only applies when substituting template arguments for parameters in the definition of a template. Your serialize
functions are member functions of a class template, they are not themselves function templates. The direct answer would be to convert the functions into function templates (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));
}
};
I've removed the redundant inline
s since all functions defined in a class body are implicitly inline, and I relocated the Serializer<HLVariant>
specialization to ensure that it is properly declared before being referenced. It's a bit silly to have a class with only static member functions; you could more reasonably implement this as a set of overloaded functions (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());
}
Given that SFINAE use hampers code readability, I would prefer to use tag dispatching in this instance. Instead of managing overload resolution of two functions with SFINAE, have a third function that calls the appropriate implementation for POD or non-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 is powerful, but dangerous enough to be left safely locked away for problems that you can solve with simpler tools.