Suppose I want to serialize the following data in the following way. Some of the data is memcopy serializable, and some is not.
MemCpySerializable ser;
NonMemCpySerializable nonser;
const std::vector<MemCpySerializable> vec1;
const std::vector<NonMemCpySerializable> vec2;
FastBinarySerializer<MemCpySerializable>::SerializeValue(ser);
FastBinarySerializer<NonMemCpySerializable>::SerializeValue(nonser);
FastBinarySerializer<std::vector<MemCpySerializable>>::SerializeValue(vec1);
FastBinarySerializer<std::vector<NonMemCpySerializable>>::SerializeValue(vec2);
The previously mentioned types are defined in this way:
template<typename T>
struct IsMemcopySerializable
{
static constexpr bool value = std::is_trivially_copyable<T>::value && std::is_trivially_destructible<T>::value &&
!std::is_pointer<T>::value;
};
struct MemCpySerializable
{
};
template<>
struct IsMemcopySerializable<MemCpySerializable>
{
static constexpr bool value = true;
};
struct NonMemCpySerializable
{
};
template<>
struct IsMemcopySerializable<NonMemCpySerializable>
{
static constexpr bool value = false;
};
As you can see, the only difference in the two struct types is the value in IsMemcopySerializable::value.
Note that IsMemcopySerializablestd::vector<T>::value is false for all T.
We define FastBinarySerializer in the following way:
//Default Template Arguments
struct DefaultType;
struct NonDefaultType; //This is unused, but it may be helpful as a default template argument.
//Primary Template
template<typename T, typename U = DefaultType, typename Enable = void >
struct FastBinarySerializer;
template<typename T, typename U>
struct FastBinarySerializer<
T,
U,
typename std::enable_if<
IsMemcopySerializable<T>::value>::type>
{
static void SerializeValue(const T& value) noexcept
{
//Memcopy serialization
}
};
template<typename T, typename U>
struct FastBinarySerializer<
T,
U,
typename std::enable_if<
!IsMemcopySerializable<T>::value>::type>
{
static void SerializeValue(const T& value)
{
//Fallback case. This will only work for specific types (not std::vector<T>).
// We will assume that any nonspecialized type T with !IsMemcopySerializable<T>::value
// will be handled by this function.
}
};
template<typename T>
struct FastBinarySerializer<std::vector<T>, DefaultType, void>
{
static void SerializeValue(const std::vector<T>& value)
{
FastBinarySerializer<uint32_t>::SerializeValue(value.size());
for (auto& item : value)
{
FastBinarySerializer<T>::SerializeValue(item);
}
}
};
The problem is that the following line generates this error:
FastBinarySerializer<std::vector<MemCpySerializable>>::SerializeValue(vec1);
//error C2752: 'FastBinarySerializer<std::vector<MemCpySerializable,
//std::allocator<MemCpySerializable>>,DefaultType,void>': more than one partial specialization
//matches the template argument list
The issue is that std::vector is not MemcopySerializable. The FastBinarySerializer class template matches two of the specializations. Is there a way that I can make FastBinarySerializerstd::vector<NonMemCpySerializable> match only with the std::vector specialization? I tried to use DefaultType and NonDefaultType to enforce that the std::vector specialization was prioritized to no avail.
My constraints: FastBinarySerializer must remain as a class template and not as a function template. SerializeValue must have the same function signature throughout. I cannot manually specify DefaultType or NonDefault type in the class template instantiation.