A trait class to detect whether a template is specialized for a given type 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&lt;typename...&gt;
struct voider
{
    using type = void;
};

template&lt;typename... TT&gt;
using void_t = typename voider&lt;TT...&gt;::type;


Here is the template utility I wrote to detect whether a template has a specialization for a given type, for SFINAE purpose:

template&lt;
    template&lt;typename...&gt; class,
    typename,
    typename=void
&gt;
struct is_specialized:
    std::false_type
{};

template&lt;
    template&lt;typename...&gt; class Template,
    typename T
&gt;
struct is_specialized&lt;Template, T, std::void_t&lt;decltype(Template&lt;T&gt;{})&gt;&gt;:
    std::true_type
{};


And here is a small example of how it can be used:

template&lt;typename T&gt;
struct foo;

template&lt;&gt;
struct foo&lt;int&gt; {};

template&lt;&gt;
struct foo&lt;float&gt; {};

int main()
{
    // Should print 1 1 0
    std::cout &lt;&lt; is_specialized&lt;foo, int&gt;::value &lt;&lt; ' '
              &lt;&lt; is_specialized&lt;foo, float&gt;::value &lt;&lt; ' '
              &lt;&lt; is_specialized&lt;foo, double&gt;::value;
}


Is there any way I could improve this specialization trait? Any kind of review is welcome :)
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 &lt;typename T&gt; struct foo { };
template &lt;&gt; struct foo&lt;int&gt; { };

// is foo&lt;X&gt; the primary or the specialization?


Back to your example - just because you cannot construct an object of a particular instantiation (e.g. foo&lt;double&gt;) 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 &lt;typename, typename=void&gt;
struct is_specialized : std::false_type
{};

template&lt;typename T&gt;
struct is_specialized&lt;T, void_t&lt;decltype(T{})&gt;&gt;
    : std::true_type
{};


Which you would use as is_specialized&lt;foo&lt;int&gt;&gt;::value (true) or is_specialized&lt;foo&lt;double&gt;&gt;::value (false). 

But really, since we're just testing for constructibility, we should just use what's in the standard:

template &lt;typename T&gt;
using is_specialized = std::is_default_constructible&lt;T&gt;;