# static_assert in templates

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.
{"ft_lang_label":"__label__en","ft_lang_prob":0.81175226,"math_prob":0.91059,"size":4281,"snap":"2020-45-2020-50","text_gpt3_token_len":1007,"char_repetition_ratio":0.1416881,"word_repetition_ratio":0.14942528,"special_character_ratio":0.25040877,"punctuation_ratio":0.13277511,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9722591,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2020-11-28T04:52:54Z\",\"WARC-Record-ID\":\"<urn:uuid:27bbf0dc-08c3-40ab-869f-30c358c6ce11>\",\"Content-Length\":\"71269\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:a0dedb68-8d04-419f-b12b-a42daf1962f7>\",\"WARC-Concurrent-To\":\"<urn:uuid:d6cc0b78-1a2e-4b15-bee2-90360d43d35b>\",\"WARC-IP-Address\":\"192.0.78.13\",\"WARC-Target-URI\":\"https://blog.knatten.org/2018/10/19/static_assert-in-templates/\",\"WARC-Payload-Digest\":\"sha1:S2UKYWGSSWTHWI4VTVXBNSOUYO4FVOD4\",\"WARC-Block-Digest\":\"sha1:QNUK2SBZ2RJF7TF34WXTHYOSK4JG5DEW\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2020/CC-MAIN-2020-50/CC-MAIN-2020-50_segments_1606141195069.35_warc_CC-MAIN-20201128040731-20201128070731-00021.warc.gz\"}"}