Contracts: Evaluation Semantic

After briefly presenting the details of contracts in my last article, “Contracts: A Deep Dive“, I would like to take a closer look at the very interesting Evaluation Semantic in today’s article.

If a contract assertion occurs, one of the four evaluation semantics is applied: ignore, observe, enforce, or quick-enforce. The table provides an overview of the four semantics:

Unfortunately, it is not possible to see these evaluation semantics in full use at this time. The following implementations provide an initial impression on Godbolt: Clang and libc++ integration, as well as GCC.

First, I would like to discuss the difference between checking semantics and terminating semantics.

Checking Semantic and Terminating Semantic

While checking semantics evaluates the contract assertion, terminating semantics also terminate the program.

Now I finally come to evaluation semantics.

Evaluation Semantic

A standard-compliant implementation does not have to implement each of the four evaluation semantics: ignore, observe, enforce, and quick-enforce. It can also offer its own semantics.

ignore

As the name suggests, this semantics ignores the evaluation of the predicate. Nevertheless, the predicate must be syntactically correct.

observe

The observe semantics is a so-called checking semantics. Three conditions can, in general, lead to a contract violation:

  • 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.

If a contract violation occurs at compile time, a diagnostic is produced, and the compilation continues.

If a contract violation occurs at runtime, the contract-violation handler is invoked, referring to an object of type const std::contracts::contract_violation containing information about the contract violation. If the contract-violation handler returns normally, program execution continues.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Embedded Programming with Modern C++": (open)
  • "Generic Programming (Templates) with C++": (open)
  • "Clean Code: Best Practices for Modern C++": September 2025
  • Do you want to stay informed: Subscribe.

     

    enforce

    The enforce semantics will invoke the contract-violation handler at runtime. The program will terminate if the contract-violation handler returns normally. The enforce semantics is a so-called terminating semantics. This means that in the event of a contract violation, program execution is terminated. After that, one of the following actions may occur:

    • Invoke std::terminate.
    • Invoke std::abort.
    • Terminate execution immediately.

    Compilation is aborted at compile time.

    quick-enforce

    The quick-enforce semantics will not invoke the contract-violation handler at runtime. As a terminating semantics, it will immediately terminate the program. In this case, __builtin_trap() is used, for example.

    Compilation is aborted at compile time.

    Now, of course, I will discuss the contract violation handler.

    Contract Violation Handler

    The contract-violation handler has the following signature:

    void handle_contract_violation( std::contracts::contract_violation );
    

    The implementation provides the default contract-violation handler. However, the implementation may also allow this default contract-violation handler to be replaced by a user-defined one.

    In his excellent presentation Contracts for C++ at ACCU 2025, Timur Doumler presents some exciting examples of user-defined contract violation handlers:

    • Logging
    void handle_contract_violation( std::contracts::contract_violation violation ) {
        LOG(std::format("Contract violated at: {}\n", violation.location()));   
    }
    
    • Set a breakpoint
    void handle_contract_violation( std::contracts::contract_violation violation ) {
        std::breakpoint();
    }
    
    • Wait until a debugger is attached
    void handle_contract_violation( std::contracts::contract_violation violation ) {
        while (!std::is_debugger_present())
         /* spin */
    
        std::breakpoint();
    }
    
    • Print a stacktrace
    void handle_contract_violation( std::contracts::contract_violation violation ) {
        std::cout << std::stacktrace::current(1);
    }
    
    • Defer to the default contract-violation handler
    void handle_contract_violation( std::contracts::contract_violation violation ) {
        std::cout << std::stacktrace::current(1);
        std::contracts::invoke_default_contract_violation_handler(violation);
    }
    

    Finally, I would like to introduce the interface of the std::contracts::contract_violation object that the contract-violation handler receives.

    std::contracts::contract_violation

    • kind: returns the kind of contract assertion violated
    • semantic: returns the evaluation semantics when the contract violation occurs
    • is_terminating: returns whether the evaluation semantics is terminating
    • detection_mode: returns the reason that causes the contract violation
    • evaluation_exception: returns an std::exception_ptr to the exception thrown from the predicate evaluation
    • comment: returns the explanatory string about the contract violation
    • location: returns a std::source_location indicating the location of the contract violation

    More information about the std::contracts::contract_violation object can be found on the cppreference page.

    What’s next?

    In my next article, I will focus on the smaller features in C++26. I’ll start with the small safety features in the core language.

    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)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 15561 737372
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org