detection idiom and default parameter type match

54 Views Asked by At

I can write the following to detect, if an object is serializable.

template <typename T, typename = int>
struct is_serializable : std::false_type {};

template<typename T>
struct is_serializable <T, decltype(std::declval<std::ostream>() << std::declval<T>(), 0)> : std::true_type { };

template <typename T>
constexpr bool is_serializable_v = is_serializable<T>::value;

I do understand that this is expression SFINAE and the overload is only selected if the type of the expression is deducible. Otherwise the default implementation is chosen. But why must the resulting type of the decltype expression match the type of the default parameter. If I write the following code it does no longer work:

template <typename T, typename = int>
struct is_serializable : std::false_type {};

template<typename T>
struct is_serializable <T, decltype(std::declval<std::ostream>() << std::declval<T>(), 0L)> : std::true_type { };

template <typename T>
constexpr bool is_serializable_v = is_serializable<T>::value;
1

There are 1 best solutions below

2
On BEST ANSWER

In the second case, you "specialize"

struct is_serializable <T, long> // For T serializable

but you request in is_serializable_v the type is_serializable <T, int> which will never match with your specialization.

Some default parameter explanation:

template <typename T, typename = int>
struct is_serializable : std::false_type {};

// Specializations...

can be seen as

template <typename T, typename = int>
struct is_serializable;
// So writing is_serializable<T> would be is_serializable<T, int>

template <typename T, typename>
struct is_serializable : std::false_type {};
// fallback for any combination not in specialization
// as <NonSerializable, int> <NonSerializable, std::string>
// <Serializable, string>
// but not <Serializable, int> which is part of specializations

// Specializations...