SFINAE stands for "Replacement Error - This Is Not An Error." By definition, this means that it applies only when replacing template arguments with parameters in the template definition. Your serialize functions are member functions of a class template; they themselves are not functional templates. The direct answer will be the conversion of functions to function templates ( Live code ):
template <typename> struct Serializer; template <> struct Serializer<HLVariant> { static CByteArray serialize(const HLVariant& ) { 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& ) { 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 removed the redundant inline , since all functions defined in the class of the class are implicitly built-in, and I moved the Serializer<HLVariant> specialization to make sure that it is correctly declared before the link. It's a little silly to have a class with only static member functions; you can more intelligently implement this as a set of overloaded functions ( Live code ):
inline CByteArray serialize(const HLVariant& ) { return CByteArray(); } template <typename T> inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& ) { 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 using SFINAE makes code difficult to read, I would prefer to use the tag dispatch manager in this instance. Instead of controlling the overload resolution of two functions using SFINAE, there is a third function that calls the appropriate implementation for POD or non-POD ( Even more live code ):
inline CByteArray serialize(const HLVariant& ) { return CByteArray(); } template <typename T> inline CByteArray serialize(std::true_type, const T& ) { 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 safe to block for problems that you can solve with simpler tools.
Casey source share