Contracts: A Deep Dive
I already introduced contracts in the article “Contracts in C++26”. In this article and the next ones, I will dive deeper into the details.

In this article, I refer mainly to the excellent proposal “Contracts for C++”. Unfortunately, proposal P2900R14 exceeds 100 pages in length. I will therefore try to summarize the most important points briefly and concisely. If in doubt, however, you should consult the proposal itself.
I like to begin this article with a few basic definitions, which are essential for a deeper understanding of contracts. If this definition seems too abstract to you, read my introductory article “Contracts in C++26”.
What are Contracts?
A contract specifies interfaces for software components in a precise and checkable way. These software components in C++26 are functions and methods. The contract is a set of conditions.
A contract violation occurs when a condition of the contract is not fulfilled. A contract violation can occur for three reasons:
- The evaluation of the predicate returns
false
. - The evaluation of the predicate causes an exception.
- The evaluation of the predicate occurs at compile time, but the predicate is not a constant expression.
A correct program is a program that does not violate the contract.
The conditions fall into three categories:
- A precondition: a predicate that is supposed to hold upon entry into a function.
- A postcondition: a predicate that is supposed to hold upon exit from the function.
- An invariant: a predicate that is supposed to hold at its point in the computation.
The precondition and the postcondition are placed outside the function definition, but the invariant is placed inside the function definition. A predicate is an expression that returns a boolean.
These predicates, used to check the contract, are called contract assertions.
Here is a concrete example of the proposal. In this example, contract_assert
stands for the invariant.
int f(const int x) pre (x != 1) // a precondition assertion post(r : r == x && r != 2) // a postcondition assertion; r names the result object of f { contract_assert (x != 3); // an assertion statement return x; }
The following calls to function f
show the contract violations.
void g() { f(0); // no contract violation f(1); // violates precondition assertion of f f(2); // violates postcondition assertion of f f(3); // violates assertion statement within f f(4); // no contract violation }
A few Restrictions
A few restrictions still apply to contracts. At this point, virtual functions cannot contain preconditions or postconditions. This will likely change with future standards.
Similar restrictions apply to defaulted and deleted functions. The first declaration of these functions must not contain any preconditions or postconditions.
Of course, restrictions also applied to constructors and destructors. Preconditions in constructors can only access non-static data members of the class using the this
pointer. The same applies to postconditions in destructors.
Now there are two important questions left to answer:
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
- When are contract assertions evaluated?
- What is the semantics of contract assertion evaluation?
Point of Evaluation
This question can be answered directly with the proposal P2900R14:
Precondition assertions are evaluated immediately after function parameters are initialized and before entering the function body. Postcondition assertions are evaluated immediately after local variables in the function are destroyed when a function returns normally. Assertion statements are executed at the point in the function where control flow reaches them.
Evaluation Semantic

The proposal suggests four evaluation semantics: ignore
, observe
, enforce
, and quick-enforce.
However, an implementation can also implement its semantics. The selection of the evolution semantics depends on the implementation. It can offer semantic selection at compile time, link time, load time, or run time. The most likely option is selection via compiler flags. The following flag is used for the Clang and GCC compilers to apply the evaluation semantics ignore
: -fcontract_semantic=ignore
. However, it is also conceivable that the selection is made via configuration files or hooks in the executable.
By default, enforce semantics should apply at run-time. An appropriate default configuration for an optimized release build should enforce semantics at compile time but ignore semantics at runtime.
What’s next?
In my next article, I will conclude my in-depth look at contracts. In particular, I will take a closer look at the four evaluation semantics: ignore
, observe
, enforce
, and quick-enforce
.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, Honey Sukesan, bruce_lee_wayne, Silviu Ardelean, schnapper79, Seeker, and Sundareswaran Senthilvel.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | ![]() |
My special thanks to PVS-Studio | ![]() |
My special thanks to Tipi.build | ![]() |
My special thanks to Take Up Code | ![]() |
My special thanks to SHAVEDYAKS | ![]() |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org