September 6, 2020·6 min read·engineeringcppstandardscompatibilityreleases

C++20 passes its final technical approval ballot

C++20's DIS ballot passes unanimously. Approval fixes the standard's technical destination while implementations and application adoption remain separate work.

A language standard needs a point at which its technical design stops changing through the approval process. C++20 has reached that point. Herb Sutter's September 6 announcement reports that the Draft International Standard ballot ended on September 4 with unanimous approval. ISO editorial work remains before publication.

That milestone differs from the February completion of technical work in Prague. The committee completed its design work then and advanced the document through the next stage. The ballot now supplies final technical approval. Publication is still a subsequent step.

For programmers, those distinctions explain what has become stable. The standard's technical content has an approval result. A compiler's implementation of that content remains a separate question, and a product's dependency set creates another boundary. Using the name C++20 for all of those questions can obscure the evidence behind each answer.

I value the runtime efficiency that C++ abstractions can provide, but a language revision also adds concepts that a maintainer must recognize. An approved document gives that learning and implementation work a definite reference. It does not remove the cost of introducing another language era into existing source.

Approval establishes a common specification

The final ballot lets implementers work from technically approved content. That is useful because disagreement about an implementation can then be framed against a shared document. The question is which rule applies and whether the implementation follows it.

Before that point, some uncertainty can concern the target itself. A design under discussion can change in response to review. After technical approval, ordinary implementation work has a more definite basis, even though later defect handling remains a distinct process.

For application authors, the practical gain is a more precise compatibility vocabulary. A project can identify a facility in the approved revision and state which implementation it needs. That is more useful than asking whether a compiler is generally new enough.

The distinction also helps documentation. A library can explain that it depends on a language facility without implying that every compiler accepting a C++20 flag implements it completely. The requirement belongs to the source. The support claim belongs to the actual toolchain.

A successful build supplies evidence about one combination of source and tools. It does not prove support for every facility in the revision. An implementation-status claim needs a scope, just as an application's use of the revision needs a scope.

Facilities have boundaries inside the language

Constant-evaluated allocation gives a concrete example. The P0784R7 design describes transient allocation, where storage created during constant evaluation is released before that evaluation completes. Its history records removal of the broader non-transient design.

That boundary matters to the way a programmer uses the facility. A calculation can obtain scratch storage and produce an independent result. It cannot infer from the presence of allocation that an arbitrary dynamically allocated object can persist as its final constant result.

The distinction gives the feature a manageable contract. Working memory can have a temporary role during the calculation. The resulting value must fit the rules of the context in which the program uses it. A library implementation then needs operations suitable for that evaluation.

This is why a brief description such as compile-time allocation is insufficient for adoption. It names the area but omits the lifetime requirement that determines whether a program is valid. Reading the feature's boundary is part of understanding what the approved revision supplies.

The same principle applies to other substantial additions. A syntax keyword identifies a mechanism, while the surrounding rules define the operation. A program needs those rules to explain its behavior across ownership and implementation boundaries.

Compiler and library support can advance separately

The GCC 10.1 announcement describes C++20 progress on both compiler and library sides. That is a useful distinction because some source depends mainly on language parsing and semantics, while other source needs new declarations and runtime components.

A template using a user-defined concept can have a different dependency set from code that uses a new standard-library facility. The compiler must understand the relevant syntax. A library component also needs a corresponding implementation available through the selected headers and linked environment.

Toolchains can combine components in different ways. Consequently, identifying the compiler executable alone can leave an incomplete account of the environment. The source's requirements need to be compared with the components that actually interpret and supply them.

For a product built from multiple libraries, the boundary extends further. Some dependencies may be built with different language modes. Whether those components can interact depends on their public interfaces and supported binary combinations. The standard's approval does not itself establish that every combination is compatible.

This is a practical reason to keep adoption claims specific. A component can use an approved facility internally without exposing it through its public interface. Another component can make that facility part of its public contract. Those choices create different requirements for downstream consumers.

A regular release need not promise a fixed feature set

Sutter's September report also describes continued work through virtual meetings and a schedule-based model for future revisions. The process aims to advance features when they are ready, rather than delay an entire revision until every desired feature is complete.

This separates a priority from a commitment. A committee can devote substantial attention to an area while leaving its inclusion dependent on the readiness of the actual proposal. The release schedule creates a decision boundary, not proof that each prioritized item will meet it.

The effect is to make the unit of progress more precise. A paper can be worth developing without being ready for adoption. A technically complete revision can proceed while related proposals continue on a later track. Neither state requires describing the other work as abandoned.

That is useful for implementers because a revision needs a target they can ship. It is useful for users because a completed set of changes can become available without waiting for every long-running design. The cost is that some related facilities can arrive at different times.

Those gaps need clear explanations. If a language mechanism is approved while convenient library support remains future work, users need to know which layer they must supply. A schedule-based process can accommodate that separation, but documentation still has to make it understandable.

Existing code keeps its own migration requirements

An approved revision does not require an application to adopt every addition at once. A codebase can introduce a facility where it solves a specific problem and preserve a simpler interface for its consumers. That makes the migration a series of concrete design decisions.

For example, using transient allocation inside a constant-evaluated helper can change the implementation of a derived constant without requiring callers to understand its scratch storage. The public result may remain an ordinary value. The implementation gains a more suitable algorithm while preserving a narrow consumer contract.

A new public template interface has a different effect. Its constraints become part of what consumers must understand and what their compiler must accept. That can improve the contract, but it also changes the source requirements across the boundary.

I prefer evaluating those changes at the component level. A feature should give a particular requirement a clearer representation or remove a specific implementation workaround. Its presence in an approved revision supplies a common definition, while the component still needs a reason to use it.

The same scope helps when a dependency cannot adopt the revision yet. A component whose public interface does not require the new facility may still use it internally within a supported build. When the interface exposes the requirement, consumers need an explicit compatibility statement. The decision follows the boundary through which the components communicate.

That keeps the practical significance of approval in view. The ballot settles the technical progression of the document. Implementers can target it, and libraries can identify dependencies against it. Applications can then make scoped adoption decisions based on the interfaces they actually expose.

The remaining editorial work and publication do not change the distinction between those responsibilities. C++20 now has final technical approval. A project's useful next statement is which approved facilities its source requires and which supported toolchain combinations provide them, including the library and binary boundaries through which that source interacts.