C++20 finishes technical work in Prague
The Prague meeting completes C++20's technical work. The remaining approval process and implementation work matter separately from the agreed language design.
Finishing a language revision requires the committee to stop changing its technical content. It does not make every implementation complete or turn every proposed application of the language into a finished library. Herb Sutter's February 15 Prague report records that WG21 has completed C++20's technical work. The meeting addressed national-body comments without adding or removing features, and the document still needs its international approval ballot.
That boundary is useful for programmers deciding what the name C++20 means. The committee now has an agreed technical document to advance. A particular compiler and standard library still have their own account of what they implement. A project's use of the revision depends on those concrete implementations.
I value C++'s ability to express abstractions whose runtime cost can remain small, but reading a large codebase already requires understanding several eras of the language. A substantial revision needs to justify its new concepts through the problems they solve. Technical completion gives implementers a more stable target for that work.
A constraint belongs at the template interface
Concepts address part of the relationship between a generic function and the types supplied to it. A template body can contain requirements that are invisible in a short declaration. If those requirements fail only during instantiation, the caller may receive an explanation through implementation details.
Andrew Sutton's concepts wording paper P0734R0 describes requires-expressions and associated constraints. The important mechanism is that the template's interface can state requirements on types and expressions. Those requirements participate in whether the constrained function is usable.
A small illustrative concept can name the operation a function intends to require.
template<class T>
concept Incrementable = requires(T value) {
++value;
};
template<Incrementable T>
void advance_once(T& value)
{
++value;
}
This example requires the expression to be well formed. Its name does not establish a complete mathematical account of incrementing every possible user-defined type. A stronger abstraction needs stronger stated requirements and any applicable semantic contract.
The distinction is important because a constraint can improve the location of a failure without proving every aspect of correctness. A type may provide an operator with behavior unsuitable for an algorithm. Generic code still needs an explanation of what the accepted operations mean.
For library design, the benefit is that this explanation can begin at the interface. A caller no longer has to infer all syntactic requirements from a body that may involve many helper templates. The implementation can reject an unsuitable type through a requirement that the author chose to expose.
Range algorithms need lifetime information
Ranges introduce another relationship that a generic signature must express. An algorithm can receive a wrapper around elements and return an iterator. Whether that result remains usable depends on which objects the iterator needs after the call.
Barry Revzin's conditionally safe ranges proposal gives a concrete example of the design work involved. A temporary reversing wrapper over a referenced string need not own the string's storage. Treating every such wrapper as an equally dangerous temporary can reject a useful result.
The point is not that temporary ranges are universally harmless. Some iterators need state in their parent view, and the underlying owner must still remain alive. The library needs to distinguish these dependencies if it is to provide useful type-based protection.
This is an example of why final specification work includes interactions among features. A range interface can look correct in isolation and still impose an unnecessarily strict rule on a composition. The complete design needs to account for what adapters preserve and what dependencies they introduce.
For application authors, the resulting abstraction remains a lifetime contract. A type can express independence from one wrapper without extending the lifetime of the actual elements. Understanding that scope prevents a useful library guarantee from becoming a mistaken claim of complete memory safety.
Coroutine syntax needs supporting abstractions
Gor Nishanov's P0912R5 describes merging the Coroutines TS into the C++20 working draft. The merge introduces coroutine language facilities and their supporting header into the standard document. This establishes machinery through which a function can participate in suspension and resumption.
The language machinery does not by itself choose an application's asynchronous interface. A program still needs types that define the behavior of its coroutine results and operations. The distinction matters when interpreting a short example containing co_await. Its meaning includes the participating types, not just the keyword.
A library can choose when work begins and how it exposes a result. Another library can make different choices while using the same language facility. A programmer integrating either one needs its lifetime and completion rules.
Sutter's report identifies additional coroutine library support as a priority for the next revision. That explains why technical completion of C++20 can coexist with substantial remaining usability work. The committee has standardized a mechanism while also identifying library work that can make common use cases more direct.
For code that manages resources, suspension adds a practical question about when scope ends. A local object can remain part of suspended work. The application's ownership account needs to include that duration and the operation that eventually completes or destroys the work.
RAII remains useful in that setting, but it cannot remove the need to identify the owner of a suspended computation. A library interface has to make that relationship understandable to its callers. The language gives implementations a common mechanism on which to build the relationship.
Compatibility is a separate design decision
The Prague report also records discussion of ABI stability. The committee did not commit to preserving every ABI indefinitely, but it also declined a broad break across the entire standard library. It invited concrete proposals whose benefits might justify migration for affected interfaces.
That position is relevant to the way language improvements reach existing systems. A source-compatible change can still affect how separately built components agree about representation or calls. A program assembled from libraries needs an account of those binary interfaces as well as its source language mode.
An unrestricted promise to preserve every existing binary choice would constrain future implementation improvements. An unrestricted willingness to break them would impose migration costs on users. Evaluating a concrete proposal lets the discussion identify both the benefit and the components that pay that cost.
I prefer that specific form of the question. A claim that a language needs modernization says little about a particular library boundary. An actual proposal can name the affected types and explain how users move between implementations.
The same discipline applies to adopting C++20 in a product. The revision's technical completion establishes the committee's document. It does not establish that a particular mix of compiler, library, and existing binary dependencies implements every needed agreement.
Completion gives the next work a defined starting point
The report distinguishes priorities for future work from commitments to deliver particular features. That is useful when reading the committee's next steps. An area can receive concentrated attention without having a finished specification ready for adoption.
For current users, technical completion means that C++20's remaining progression can begin from agreed content. Implementation work can target that content, while library authors can explain which facilities their interfaces require. The question becomes more concrete than whether a project broadly supports modern C++.
A constrained function can identify the expressions it requires. Range algorithms can expose results appropriate to an iterator's lifetime dependency. A coroutine library can define the ownership and completion rules around the standardized mechanism. Each case shows how useful adoption depends on a specific contract that a programmer can read.
This also makes documentation more precise. A library can explain that its generic interface needs a particular constraint facility, instead of asking users to assume that every implementation of the revision behaves identically. When an implementation lacks that facility, the missing requirement has a name. The same applies to a component whose public types cross a binary boundary. Its compatibility statement needs to identify that boundary and the supported build combinations. A language revision supplies common definitions for that discussion, while the component still owns the promise it makes to callers.
The Prague milestone gives those contracts a common technical reference. The next practical step for an implementation is to make its support correspond to that reference, and for a library to identify the subset on which its callers may rely. That remains distinct from the international approval ballot that follows the committee's completed technical work.