Static assert in template specialization fails even if it is not instantiated

Viewed 1014

The following code compiles fine:

#include <type_traits>

template <typename T> struct dependent_true : std::true_type { };
template <typename T> struct dependent_false : std::false_type { };

template <bool B = false>
class X { static_assert(dependent_false<X>::value); };

template <>
class X<true> { static_assert(dependent_true<X>::value); };

int main() {
   X<true> x;
}

That is, the static_assert in the primary template is not evaluated. On the contrary, if I switch to:

template <bool B = false>
class X { static_assert(dependent_true<X>::value); };

template <>
class X<true> { static_assert(dependent_false<X>::value); };

int main() {
    X<false> x;
}

Then, the static assertion in template specialization fails, even if it is not instantiated. I just wonder why. I observed this behavior with GCC 8 and Clang 6 (-std=c++17).

Live demo: https://wandbox.org/permlink/MOWNLnGMgmuDA2Ht

2 Answers

template <> class X<true> {/* ... */}; - is not a template anymore.

[temp.expl.spec]/5

A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required. In this case, the definition of the class template explicit specialization shall be in scope at the point at which the member is defined. The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization. Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.

The specialization is just like a regular class. It's not a template, and nothing is dependent. Therefore dependent_false<X>::value is just a constant expression that evaluates immediately to false. So the static assertion is immediately triggered.

Even non-instantiated template parts should be valid C++ code. static_assert(false) makes the program ill-formed. So you have your specialization with static_assert which is known on compile time to be false and your program becomes ill-formed. You have no non-resolved template parameters on your class which is used in static_assert to make compiler wonder; it knows exactly that it is false.

The same goes to if constexpr, you also can't use static_assert with expressions known to be false even if the part where this static_assert is located always gets discarded.

Related