traits if a type `T` has a `template<> struct Writer<T>` to serialize itself

Viewed 85

I have a Writer struct to do some serialization

template<typename T>
struct Writer {};  // only specialized version has ::wrap_t

template<>
struct Writer <int> {
    typedef int wrap_t;
};
template <typename T>
using Writer_wrap_t = typename Writer<T>::wrap_t;

template<>
struct Writer<float> {
    typedef float wrap_t;
};

And I want to know whether a type has a specialized Writer. The code does not work as expect:

template<typename T, typename U = Writer_wrap_t <T>>
struct has_writer : std::true_type {};

template<typename T>
struct has_writer<T, void> : std::false_type {};

int main() {
    bool b = has_writer <double>::value;
    // error C2794: 'wrap_t': is not a member of any direct or indirect base class of 'Writer<T>'
    // error C2976: 'has_reflect': too few template arguments
    // error C2938: 'Writer_wrap_t ' : Failed to specialize alias template
}

I suppose that has_writer<double> didn't use the specialized version struct has_writer<T, void> : std::false_type {};?

But now there is a substitution failure for the first one, shouldn't the compiler try to instantiate the second version?

1 Answers

You're not using SFINAE correctly. The typical pattern is to define a primary template where the second template parameter is void

template<typename T, typename = void>
struct has_writer : std::false_type {};

and then specialize the template using std::void_t of whatever type you want to check as the second parameter

template<typename T>
struct has_writer<T, std::void_t<Writer_wrap_t <T>>> : std::true_type {};

If the type you pass to void_t is well-formed, the specialization is chosen, which is the true case, otherwise the primary is chosen, which is the false case. Writer_wrap_t itself is only well-formed if the type passed to it has a member typedef wrap_t.

Related