Reputation: 9292
I have a template function defined only for some types:
template<typename T, std::enable_if_t<std::is_pod_v<T>, bool> = true >
void serialize(const T & t) { /*serialize POD*/ }
template<>
void serialize(const std::string & t) { /*serialize string*/ }
//....
And I would like to add a std::vector specialization that matches only if T can be serialized
template<typename T /*, is_serializable<T> */>
void serialize(const std::vector<T> & t) { /*do something*/ }
How can I make this one matching only if T himself matches a serialize() method?
Upvotes: 1
Views: 88
Reputation: 25536
Pre-C++20 solution: Test if you can serialize a type:
template <typename T>
auto is_serializable(T) -> decltype(serialize(std::declval<T>()), std::true_type());
std::false_type is_serializable(...);
template <typename T>
bool constexpr is_serializable_t
= decltype(is_serializable(std::declval<T>()))::value;
With this you can apply the same pattern as you had for the POD types already:
template<typename T, std::enable_if_t<is_serializable_t<T>, bool> = true >
void serialize(std::vector<T> const& t)
{ /*do something*/ }
Demonstration on godbolt.
Edit according to comments:
Actually it does not appear meaningful to serialise a std::vector
without serialising all of its elements contained. So the most simple solution (KISS principle...) is: Just doing the serialisation witout adding any tests at all!!!
template<typename T>
void serialize(std::vector<T> const& v)
{
// you'd most likely need:
serialize(v.size());
// but other variants are be possible, too, like e.g. COBS encoding the data,
// then last element to be added, when deserializing again, would be followed
// by the sole 0 (or whatever other sentinel) character encountered...
for(auto& t : v)
{
serialize(t);
}
}
The vector would start to serialise its elements, and these then, if yet other vectors, would just do the same – until reaching the base case where T isn't a vector any more. And now the final decision is made: Does an overload exist handling this final T or not, accordingly the code compiles or not ;)
Demonstration on godbolt.
Upvotes: 1
Reputation: 2859
SFINAE variant can be as simple as:
template<typename T, typename = decltype(serialize(std::declval<T>())) >
void serialize(std::vector<T> const& t)
{ /*do something*/ }
Upvotes: 2