Search code examples
c++11template-specializationstatic-assert

static_assert with partial template specialization


template<typename T, typename U = void>
struct S { /* static_assert(0, "type unsupported"); */ };
template<typename T>
struct S<T, typename std::enable_if<std::is_integral<T>::value, void>::type> {
    void foo() {}
};
...
S<int> i;
i.foo();
S<double> d;
// d.foo();

I would be expecting that the "master template" would never be instantiated for the case of int, but if I uncomment the static_assert, the S<int> instantiation will fail. Even a lone typedef S<int> Si; would fail to compile. (GCC 4.9.2 Cygwin)

What I aimed to achieve is not for S<double> to fail at the foo() call, but at the instantiation of the template itself, and that with a meaningful error message. I'm aware I can do something like typename T::nonexistent_type t; in the master template which will prevent the template for compiling, but that'd be inferior to a static_assert message. (Note: putting the static_assert within a function definition in the master template still fails compilation for S<int>)

Why does the static_assert fail even though that template is not instantiated? Is this mandated (or perhaps "unspecified") by the standard? Is there a way to fail with a static_assert the way I wish to?


Solution

  • The expression in the static_assert must be dependent on a template parameter if you wish it to be instantiation-time only. This is guaranteed by Standard- the implementation may (but has no obligation to) check static_assertions in templates that are not dependent on any template parameter.

    Your code is a strange roundabout way of doing something like

    template<typename T> struct S {
        static_assert(std::is_integral<T>::value, "type unsupported");
        void foo() {}
    };
    

    This clearly communicates to the compiler the dependency between the expression and the template parameter, and is far clearer and easier to read as well. I actually couldn't quite figure out if you wanted compilation to fail for integral types or for non-integral types.