C++ Logo

std-proposals

Advanced search

Re: [std-proposals] P4021 compile_assert() a static assert that fires at compile time, not runtime.

From: Jonathan Grant <jg_at_[hidden]>
Date: Wed, 11 Mar 2026 03:04:38 +0000
Hello Simon

Many thanks for reviewing P4021.

On 07/03/2026 06:24, Simon Schröder via Std-Proposals wrote:
>
>
>> On Mar 5, 2026, at 2:04 AM, Jonathan Grant via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> I usually use for very straight-forward things, like array access index bounds checks, or nullptr.
>
> If this is the main application area, I really don’t see the advantage over contracts. In many cases the compiler can (could?) be able to prove that the contract is always fulfilled and eliminate the check when optimization is turned on. So, it works the same if it can be proven (no runtime performance overhead). Where contracts and compile_assert differ is in cases where it cannot be proven. Contracts will just leave the check in and compile_assert refuses to compile. Outside of embedded systems I expect programmers to prefer contracts: an occasional overhead doesn’t hurt too much and I’d rather have my software working with this little overhead than having to fight a checker. Standard library hardening has shown in large projects that usually the overhead of contracts is negligible.
>

May I ask, is that C++ standard library hardening at runtime or compile time?
My personal preference would be to add a compile_assert(str != nullptr) on std::string() to prevent a nullptr ever be passed in. It still crashed last time I checked it. It did come up in a safety critical system, these nullptr do sneak through occasionally, and once is enough to crash.

May I ask, what would happen if a contract could not be eliminated by the compiler, eg a nullptr got through to an audio codec, it would call an enforcement handler at runtime? And that handler might shutdown or restart the software module audio codec?

In essence compile_assert is a compile time hard contract enforcement.

> One advantage of contracts over your proposal are the pre and post conditions that are checked (or eliminated) on every call. This means that with contracts it is not up to the programmer to remember to sprinkle compile_assert everywhere. You might even remove a compile_assert because the compiler cannot prove it. In the context of memory safety this makes compile_assert a worse choice than contracts (for everyone who can pay the tiny overhead).

That's a good point, the pre() and post() can maybe put in a header, on a declaration rather than in the module. I was thinking if I could do similar. I made an example where the pre() checks are within the header. That saves each programmer writing any compile_assert().
https://github.com/jonnygrant/compile_assert/tree/main/main13

I made two examples showing compile time contracts in C++, it has pre(), post() and contract() assert all working at compile time, this one is a percentage class:
https://github.com/jonnygrant/compile_assert/blob/main/testsuite/main28_a.cpp

Another example shows compile time contracts for a bank account class
https://github.com/jonnygrant/compile_assert/blob/main/testsuite/main25_a.cpp

I could probably move these into a hpp file and leave only the implementation in the cpp file.

Do have an idea what could be another good little example to demonstrate a compile time contract?

> On the other hand, this is a strong point to make compile_assert an option for contract enforcement. However, this means that we would need a way to skip proving to make our program compile. Maybe we can add an attribute [[no_contract_proof]] (I couldn’t quickly come up with a better name) to function calls where we don’t want a compile time check of the pre condition. Or we can have a contract_assume() that only makes assumptions for contract proving, but has no influence on optimizations like [[assume()]]. (Though the regular [[assume()]] can be used by contract proving as well.)

May I ask if you have an example of the kind of proof that might be tricky to get to pass when compiling? Something that you really need to validate, but at present cannot.

As you say projects might like to let things compile. If something is intractable, I probably would not add a compile_assert() for something really complicated (like some serious maths). Personally I would not be in favor of a compile_assert() that silently degraded to be a runtime assert() as that would terminate (or could be a serious bounds violation). I see on projects it's a slippery slope to turn off -Werror, soon particular builds have warnings that don't get fixed. (The compromise is to keep -Werror on all CI and Deliverables, but let individual programmers turn off locally during their development /briefly/)

I have got one example that at compile time it can check eg an online web API will always return a known result 0 or 1, eg not -1
https://github.com/jonnygrant/compile_assert/blob/main/testsuite/test_30_web_a.cpp

I mostly check for nullptr, and array access bounds, those have always compiled. It takes something complicated like compile_assert(5 == sqrt(25)) to fail, in clang, not gcc.

Lastly, may I ask, which is your main compiler?
Kind regards, Jonathan

Received on 2026-03-11 03:04:44