Today's question will just be about a small utility that I needed at some point for one of my projects: a template to detect whether a template is specialized for a given type. The utility uses std::void_t from C++17, but this alias template is simle enough to be implemented in you favourite C++ revision, whichever it is:template<typename...>struct voider{    using type = void;};template<typename... TT>using void_t = typename voider<TT...>::type;Here is the template utility I wrote to detect whether a template has a specialization for a given type, for SFINAE purpose:template<    template<typename...> class,    typename,    typename=void>struct is_specialized:    std::false_type{};template<    template<typename...> class Template,    typename T>struct is_specialized<Template, T, std::void_t<decltype(Template<T>{})>>:    std::true_type{};And here is a small example of how it can be used:template<typename T>struct foo;template<>struct foo<int> {};template<>struct foo<float> {};int main(){    // Should print 1 1 0    std::cout << is_specialized<foo, int>::value << ' '              << is_specialized<foo, float>::value << ' '              << is_specialized<foo, double>::value;}Is there any way I could improve this specialization trait? Any kind of review is welcome :)
A trait class to detect whether a template is specialized for a given type
c++;template;c++14;sfinae
I think there's an issue with wording here. What you're testing is if a given instantiation of a class template is default constructible. You're not testing if it's specialized. You cannot check for that. How would you differentiate between:template <typename T> struct foo { };template <> struct foo<int> { };// is foo<X> the primary or the specialization?Back to your example - just because you cannot construct an object of a particular instantiation (e.g. foo<double>) doesn't mean that you can't name the type. You can do that just fine. That lets you simplify your trait down to:template <typename, typename=void>struct is_specialized : std::false_type{};template<typename T>struct is_specialized<T, void_t<decltype(T{})>>    : std::true_type{};Which you would use as is_specialized<foo<int>>::value (true) or is_specialized<foo<double>>::value (false). But really, since we're just testing for constructibility, we should just use what's in the standard:template <typename T>using is_specialized = std::is_default_constructible<T>;