The C++29 contracts plan starts with missing interface cases
P3850 proposes a focused C++29 contracts roadmap. Virtual interfaces, evaluation control and postcondition captures address concrete limits in the C++26 facility.
A postcondition for push_back ought to be able to say that the container has one more element than it had on entry. C++26 contract assertions cannot express that comparison directly because the postcondition has no mechanism for retaining the earlier size. This limitation helps explain P3850R0, the May 12 proposal by Timur Doumler and Joshua Berne for extending contracts in C++29. The authors seek agreement on a limited set of extensions that address known gaps in the first standardized facility.
The roadmap treats C++26 contracts as an intentionally limited initial feature. It argues for independent extensions that can proceed through normal language and library review. This avoids making every improvement depend on finishing an entire expanded design. The paper also distinguishes proposals with implementation experience and complete wording from work with substantial unresolved questions.
After a decade with C++, I continue to value RAII and abstractions whose runtime cost can disappear. Contracts interest me when they make the meaning of an interface more explicit. Their value depends on whether ordinary requirements can be expressed without changing the program merely to accommodate the assertion syntax. Saving an entry-state value is a good example of a requirement that needs a precise mechanism.
Postconditions need a record of entry state
The companion P3098R2 proposal for postcondition captures, by Doumler, Gašper Ažman and Berne, supplies that mechanism. It places a capture list between post and the predicate. The captured variables are constructed when the function is called and are visible to their associated postcondition predicate. The following is proposed extension syntax, not portable C++26.
int f(int i)
post [i] (result: result >= i);
The copied i denotes the value supplied at entry. A function body can then change its own parameter without changing the value the predicate uses. This separates the initial input from the parameter object whose contents can evolve during execution.
C++26 instead restricts use of non-reference parameters in postconditions. Such a parameter must be const on the function declarations, and the function cannot be a coroutine. P3098 explains that these restrictions allow reasoning about the value without inspecting the function body. Captures provide an alternative that retains a separate value instead of requiring the body to preserve the parameter object.
The proposal deliberately excludes reference captures, default captures and captures of this or *this. It also excludes captures on preconditions and assertion statements. Familiar lambda notation therefore does not imply every lambda capture facility participates. The feature has a narrower purpose, retaining selected values across a particular function invocation.
A capture has construction and destruction semantics
Capturing an old value is not free of semantic consequences. The proposal treats constructing the captures, evaluating the predicate and destroying the captures as parts of one postcondition evaluation. All phases use the same evaluation semantic and the same caller-side or callee-side placement. If the evaluation is duplicated or elided, the phases follow that decision together.
Precondition evaluation and capture initialization follow lexical order when their declarations are interleaved. After the function returns and the postconditions run, capture destruction occurs in reverse lexical order. A capture that copies an object consequently has a defined lifetime extending across the call. Its construction and destruction can themselves fail and require specified handling.
P3098 proposes reporting exceptions from those phases through the violation handler with a new post_capture assertion kind. Noncopyable or nondestructible captured objects make the program ill-formed. These rules matter because a contract declaration can introduce operations beyond reading the final predicate. The snapshot must obey the same language rules governing the object it stores.
Virtual interfaces remain a priority
The roadmap gives first priority to pre and post on virtual functions through P3097R2. C++26 rejects those assertions on a virtual declaration. Libraries organized around runtime polymorphism therefore cannot express their public requirements in the same way as nonvirtual functions. This is a functional gap for code that uses a base interface to describe an operation.
P3850 says the virtual-function design has working GCC implementation experience and complete wording. Its previous removal from the C++26 proposal involved disagreement about the model and its experience relative to other languages. The roadmap recommends another review instead of treating that earlier exclusion as a permanent decision about where contracts belong.
The distinction matters for planning. A proposal can be mature enough to implement and still face an unsettled design judgment. The roadmap explicitly evaluates maturity alongside impact and the concerns raised during C++26 work. Its priorities are arguments about what the next cycle should finish, not announcements that those extensions have already entered the standard.
Evaluation labels address different deployment policies
P3850 also prioritizes labels that control evaluation semantics in source. The examples include checks that must always enforce, checks introduced into older code that should only observe, and expensive checks enabled in selected builds. A label can also group assertions belonging to a particular library. These use cases require more precise control than treating every assertion in a program identically.
The paper acknowledges unresolved ABI questions for always-enforced assertions. That is an important limit on the roadmap confidence. Making the desired policy expressible does not automatically resolve how separately compiled declarations and definitions agree about it. The extension needs a model that remains meaningful across library boundaries.
A library API for explicitly triggering contract violations is another priority. It would let existing assertion mechanisms use the standard violation handler while retaining their own predicate-evaluation behavior. This offers a migration path for code that cannot accept every semantic choice of language contract assertions.
Implicit checks for core-language undefined behavior and user-defined messages complete the proposed near-term set. The roadmap leaves class invariants and contracts on function pointers outside that commitment. A limited plan gives each included extension a specific purpose and review path, while keeping less mature work available for further design. For postcondition captures, the immediate purpose is concrete enough to test against an interface declaration that needs both the initial value and the final result.