Quiz time! Which of the following programs can you expect to not compile? For bonus points, which are required by the C++ standard to not compile?

Program 1

struct B{}; template <typename T> struct A { //Assume sizeof(B) != 4 static_assert(sizeof(T) == 4); }; A<B> a;

Program 2

struct B{}; template <typename T> struct A { //Assume sizeof(B) != 4 static_assert(sizeof(T) == 4); }; A<B>* a;

Program 3

struct B{}; template <typename T> struct A { //Assume sizeof(int) != 4 static_assert(sizeof(int) == 4); };

In case you’re not familiar with static_assert , it takes a constant boolean expression, and if it evaluates to false, you get a compilation error. The most basic example is just doing static_assert(false) . If you have that anywhere in your program, compilation fails. But let’s start at the beginning:

Program 1

struct B{}; template <typename T> struct A { //Assume sizeof(B) != 4 static_assert(sizeof(T) == 4); }; A<B> a;

Here we have a class template struct A , which takes a type T as its single template parameter. We then assert that the size of the provided template argument is 4 .

We then define a variable a of type A<B> . In order to do that, we need the complete definition of A<B> , so that specialization of A gets implicitly instantiated. In that specialization, sizeof(T) becomes sizeof(B) , which is not equal to 4 , and compliation fails.

Program 2

struct B{}; template <typename T> struct A { //Assume sizeof(B) != 4 static_assert(sizeof(T) == 4); }; A<B>* a;

This is the exact same problem as in Program 1, except we only define a pointer to A<B> . Does this result in a implicit instantiation? Let’s have a look at [temp.inst] (§17.7.1) ¶1 in the C++17 standard:

Unless a class template specialization has been explicitly instantiated (17.7.2) or explicitly specialized (17.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.

The class template specialization A<B> has not been explicitly instantiated nor explicitly specialized, so the question is then whether it’s implicitly instantiated. We’re only declaring a pointer to it, which doesn’t require a completely-defined object type, so it’s not instantiated. The program compiles just fine.

Program 3

struct B{}; template <typename T> struct A { //Assume sizeof(int) != 4 static_assert(sizeof(int) == 4); };

In this variation, we’re asserting on the size of int , rather than the size of the template argument. And given the assumption that sizeof(int) != 4 , that assertion will always fail. However, we’re never actually instantiating any specialization of A whatsoever. In Program 2, not instatiating the template allowed us to ignore the static_assert . Does the same apply here? In fact, it doesn’t. Let’s have a look at [temp.inst] (§17.6) ¶8 in the C++17 standard:

The program is ill-formed, no diagnostic required, if: […] a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter

The static_assert(sizeof(int) == 4) does not depend on a template parameter, so if we were to instantiate A immediately following its definition, A would always be ill-formed.

So our program is ill-formed, no diagnostic required.

Now what does that mean? ill-formed is the terminology used by the standard for a program that’s not valid C++, where compilation is required to fail with an error message. Ill-formed, no diagnostic required however means our program is not valid C++, but that the compiler isn’t required to let us know. The standard makes no guarantees on the behaviour of the program, i.e. we have undefined behaviour.

So Program 3 has undefined behaviour. In practice however, both Clang, gcc and msvc gives a compilation error in this case.

Summary

Program Because … … the standard says In practice 1 We need the class definition Compilation error Compilation error 2 We don’t need the class definition No error No error 3 The assertion doesn’t depend on T Undefined behaviour Compilation error

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.