ISO/IEC JTC1 SC22 WG21 P2131R0 Date: 2020-03-02 To: the public Thomas Köppe <tkoeppe@google.com>



Changes between C++17 and C++20 DIS

Abstract

This document enumerates all the major changes that have been applied to the C++ working draft since the publication of C++17, up to the publication of the C++20 DIS. Major changes are those that were added in the form of a dedicated paper, although not all papers are mentioned individually. The remaining papers are listed summarily below. Issue resolutions from the CWG or LWG issues lists are generally not included, but the containing papers are part of the summary listing. Defect reports that are not part of the published International Standard are marked with a “DR” superscript.

Contents

Removed or deprecated features

Document Summary Examples, notes P0619R4 Removal of various deprecated features The following features that were already deprecated in C++17 are now removed: the noexcept-specifier throw() (use noexcept instead)

(use instead) ineffective “C++ versions” of compatibility headers, <ccomplex> , <ciso646> , <cstdalig> , <cstdbool> , <ctgmath> (there is no need for those in C++ code)

, , , , (there is no need for those in C++ code) uncaught_exception (use uncaught_exceptions instead)

(use instead) functional adaptors not1 , not2 , unary_negate , binary_negate , as well as the class members result_type , argument_type , first_argument_type , second_argument_type (the functionality of bind and not_fn is strictly superior).

, , , , as well as the class members , , , (the functionality of and is strictly superior). redundant members of allocator (which are subsumed by the allocator_traits defaults): pointer , const_pointer , reference , const_reference , rebind , address , construct , destroy .

(which are subsumed by the defaults): , , , , , , , . raw_memory_iterator

temporary buffer API ( get_temporary_buffer , return_temporary_buffer )

, ) traits is_literal_type and result_of

and the member shared_ptr::unique Moreover, formerly implied special member functions are now declared explicitly throughout the standard library whenever their implicit declaration is deprecated [depr.impldec]. P1236R1 Only two’s complement representation for signed integers As of C++20, the only permitted representation for signed integers is two’s complement. Previously, no representation was specified, but due to size and layout constraints, the only possible ones were two’s complement, ones’ complement, and sign-magnitude. Support for the latter two has now been removed. P0767R1 Deprecate the notion of a “POD” type The notion of a “plain-old data” (POD) type has been superseded by the more granular notions of trivial and standard-layout, and this change removes this notion from the main language specification (though it is retained as deprecated in Annex D). P0806R2 Deprecate the implicit lambda capture of this via [=] The capture of this via [=] is now deprecated, since it is irregular and potentially confusing with [=, *this] . The capture should now be spelled [=, this] . See also P0409R2 below. P1161R3 Deprecate the comma operator in subscripting expressions The syntax a[x, y, z] is now deprecated; if this functionality is desired, it should be spelled a[(x, y, z)] . Eventual removal of the deprecated expression would open the door to extensions to the subscripting expression. P1152R4, P1831R1 Deprecate certain volatile qualifications The volatile qualifications in certain contexts where they would be of questionable value or outright broken are now deprecated. (This includes certain operands of increment/decrement and assignment expressions, function parameters, function return types, and the types of structured bindings.) P0966R1 Deprecate shrinking basic_string::reserve The default argument of the parameter of basic_string::reserve is removed and the function no longer shrinks capacity. The behaviour was inconsistent with vector::reserve and redundant with basic_string::shrink_to_fit . A deprecated zero-parameter overload has been added to Annex D.

New core language features with global applicability

These are features that may happen to you without your knowledge or consent.

Document Summary Examples, notes Core: P0734R0, P0857R0, P1084R2, P1141R2, P1452R2, P1616R1, P1972R0, P1980R0, P2092R0, P2104R0, P2113R0; Library: P0898R3, P1248R1, P1474R1, P1754R1, P1878R1, P1964R2, P2102R0. Concepts Concepts extend C++’s template facility with a way to constrain a template’s parameters. The constraints take part in overload resolution. P0912R5, P2107R0 Coroutines Coroutines are a new kind of control flow that extends the notion of a function. P1103R3, P1502R1, P1766R1, P1811R0, P1815R2, P1703R1, P1779R3, P1857R3, P1874R1, P1979R0, P2109R0, P2115R0 Modules Modules offer a new way to organize source code that is not based on textual inclusion in the way header inclusions were, but instead allows for a principled specification of component boundaries. P0515R3, P0905R1, P1120R0, P1185R2, P1186R3, P1630R1, P1614R2, P1855R0, P1946R0, P1959R0, P2002R1, P2085R0 Three-way comparison (“spaceship”) and defaulted comparisons The value of the expression a <=> b describes which one of a < b , a == b , and a > b is true.



A key part of this feature is that classes that provide this operator can have all of the six traditional, binary relational operators defined implicitly.

New core language features with local applicability

These are features where you would know if you were using them.

Document Summary Examples, notes P0329R4 Designated initializers struct X { int a; int b; }; X x { .b = 10 }; P0732R2, P1907R1 Class-types in non-type template parameters Non-type template parameters can now be of class type: struct X { /* ... */}; template <X Value> struct Y; Certain restrictions apply to ensure that value identity can be established reliably. These new kinds of non-type parameters are lvalues, unlike the existing non-class ones. P0840R2 [[no_unique_address]] An attribute that provides language support for empty or overlapping member objects. Previously, this effect was often achieved by using overlapping base class layouts (“empty base optimisation”). P0479R5 [[likely]] , [[unlikely]] Attributes to guide branch prediction. Already wide-spread as vendor extensions. P1007R3 assume_aligned A special language-support function that promises to the implementation that a pointer is aligned in a certain way (with undefined behaviour if this is not in fact true at runtime), which allows better code generation (e.g. vectorised instructions; omission of preambles). Already wide-spread as vendor extensions. P1143R2 constinit The new constinit keyword specifies a variable to be constant-initialized (and the program would be ill-formed if this is not possible). The variable can still be mutable, and indeed this is the key difference from a constexpr variable. Having constant initialization suffices to avoid any form of static initialization problems, and also allows local static variables to omit a synchronization guard on access (since there is no dynamic initialization that any thread would need to wait for). P1073R3, P1937R2 consteval The new consteval keyword specifies a function as an “immediate function”, whose invocation is always a constant expression (and which thus never requires code to be emitted from the translation). Contrast this with constexpr functions, which may, but are not required to be, used as constant expressions. P0595R2 is_constant_evaluated A special language-support function that tells whether the caller is in a constant evaluation. This allows library implementations to provide a constexpr-implementation as well as an optimised runtime implementation of the same function (whereas the constexpr implementation alone would not have optimal runtime performance, if it turned out to be needed at runtime). P0722R3 A destroying operator delete A new way to provide a deallocation function ( operator delete , taking a parameter of type std::destroying_delete_t ) with the effect that a delete-expression that would choose such a function does not call the destructor; instead, the deallocation function itself is required to call the destructor. See the paper for examples why this might be desirable. P0784R7 Constexpr new / delete Dynamic object creation and destruction may now appear in constexpr contexts, as long as every created object is destroyed. This allows, say, the use of a local std::string variable in the body of a constexpr function. P0476R2 bit_cast Despite its library-looking name, this is a core language facility that creates objects whose object representation is copied from an existing object. Importantly, the target type need not be default-constructible. Attempts to achieve this by other means, while very common, often run into undefined behaviour. Example: std::uint32_t n = std::bit_cast<std::uint32_t>(1.5f); P1099R5 using enum A way to introduce the enumerator names of a scoped enumeration.

New library features

Document Summary Examples, notes P0896R4, P1252R2, P1035R7, P1243R4, P1391R4, P1394R4, P1456R1, P1523R1, P1716R3, P1739R4, P1862R1, P1870R1, P1871R1, P1970R2, P1983R0, P1994R1, P2091R0, P2106R0 Ranges Ranges are a new model that improves on pairs of iterators. This feature consists of new taxonomy, new concepts, and new versions of the familiar standard library algorithms that live in namespace std::ranges . P0355R7, P1361R2, P1466R3, P1650R0, P1981R0, P1982R0 Calendars and time zones A large library addition to <chrono> for civil time (calendars). For example: auto date = 2016y/May/29; P0645R10, P1361R2, P1652R1, P1868R2, P1892R1 Text formatting std::string s = std::format("{}", "Hello, world"); P1135R6, P1643R1, P1644R0, P1865R1 Synchronization Waiting, notifications, semaphores, latches, barriers. P0631R8 Mathematical constants Variable templates for many mathematical constants, e.g. std::numbers::pi_v<float> , and concrete constants for double , e.g. std::numbers::pi . P1208R6 source_location A proper library type that exposes the information provided by the __LINE__ and __FILE__ macros, the __func__ variable, and column number. P0122R7, P1085R2, P1024R3, P1227R2, P1394R4, P1872R0, P1976R2, P2116R0 New class template: span A span is a light-weight reference to a contiguous range (mutable or const); essentially a “pointer and size”: A span<T> is like a T* p and a size N such that p[i] is valid for i in [0, N ). It is similar in purpose (and pitfalls) to C++17’s string_view , which is a special kind of span adapted to strings. P0660R10, P1869R1 New classes: stop_token , jthread Mechanisms for a thread manager class that joins the thread on destruction, and for interrupting the running thread. P0019R8, P1123R0 New class template: atomic_ref Atomic operations on non-atomic objects. P0550R2, P0777R1 Transformation trait: remove_cvref A composition of remove_cv and remove_reference . Previously, the slightly different decay had been popular for this use case, even though it does too much. Existing uses of decay in the specification have been replaced with the more appropriate transformations. P0318R1 Transformation traits: unwrap_reference , unwrap_ref_decay Traits to work with reference_wrapper : unwrap_reference_t<T> is U& if T is reference_wrapper<U> , and T otherwise. unwrap_ref_decay first applies decay before unwrapping. The motivating use case is the specification of make_pair ; these traits allow users to write functions with analogous handling of reference_wrapper . P0887R1 Transformation trait: type_identity type_identity_t<T> is T ; useful when a template parameter is required in a non-deduced context. P0758R1 Type trait: is_nothrow_convertible Like is_convertible , but does not throw. P1357R1 Type traits: is_bounded_array , is_unbounded_array P0466R5 Type traits: is_layout_compatible , is_pointer_interconvertible_base_of , is_pointer_interconvertible_class , is_corresponding_member P1115R3, P1209R0 Free functions erase , erase_if Free functions to provide a simple, uniform interface for erasing elements from a container. The functions return the number of erased elements; see also P0646R1 below. P1227R2, P1970R2 Free functions size , ssize One is signed, the other isn’t… P0463R1, P1612R1 Endianness detection An enum endian whose members endian::native , endian::little , endian::big describe the implementation’s endianness. P0053R7, P0753R2 Synchronized, buffered ostream A buffering ostream wrapper, basic_osyncstream , that causes all output to be emitted atomically to the wrapped ostream. Example: std::osyncstream(std::cout) << a << b << "foo" << c << '

'; Unlike in the unwrapped version, concurrent writes to cout never interleave. P0769R2 shift algorithms New algorithms for shifting the elements of a range: shift_left , shift_right P0556R3, P1355R2, P1956R1 Functions for integral power-of-2 operations has_single_bit (i.e. is a power of two), bit_ceil , bit_floor , bit_width P0553R4 Functions for bit operations Rotation ( rotl , rotr ), population count ( popcount ), count of number of successive zeros or ones from left or right ( countl_zero , countl_one , countr_zero , countr_one ). P0811R3 Functions midpoint , lerp Interpolation functions. std::midpoint(a, b) computes essentially a + b / 2 , but works with integers, floating point numbers, and pointers. std::lerp computes arbitrary linear interpolation. Both are correct even in corner cases. P0586R2 Function templates cmp_equal , cmp_less , etc. These functions provide integral comparisons that produce the mathematical result even when the operands have different types. For example, cmp_less(-1, 0U) is true , whereas -1 < 0U is false (due to arithmetic conversions). P1020R1, P1973R1 Function templates make_unique_for_overwrite , make_shared_for_overwrite , allocate_shared_for_overwrite The existing smart pointer creation functions make_unique , make_shared and allocate_shared use value-initialization when called with no constructor arguments (equivalent to new T() ). This new feature adds functions make_unique_for_overwrite , make_shared_for_overwrite , and allocate_shared_for_overwrite , which take no constructor arguments and use default-initialization (equivalent to new T ). This avoids unnecessary initialization in situations where the initial value is never read. P0356R5, P1651R0 Function template bind_front A simpler, more predictable version of bind that only binds arguments on the left. P0325R4 Function template to_array P0653R2 Function template to_address A well-defined replacement for addressof(*p) that works even when p does not point to a constructed object. P0591R4 Utilities for the uses-allocator construction P1001R2 New execution policy “unsequenced” Unsequenced execution allows for vectorization (even on a single thread).

Modifications to existing features

Document Summary Examples, notes P0482R6, P1423R3 New type: char8_t The type char8_t is analogous to the existing types char16_t and char32_t , i.e. a fundamental, unsigned integral type, sufficient to store one UTF-8 code unit. As a breaking change, the types of u8 character literals (C++17, e.g. u8'a' ) and u8 string literals (C++11, e.g. u8"foo" ) are now char8_t and array of char8_t , respectively; previously they were (array of) char . This breakage was deemed to be minor, since both of those features had not been widely used. This change enables overload resolution to distinguish intended UTF-8 from native encoding, which previously was only distinguished by the choice of literal, but not by the type of the literal value. P1041R4 Makes char16_t / char32_t literals be UTF-16/32 This requires that char16_t literals (e.g. u"foo" ) be encoded as UTF-16 and char32_t literals (e.g. U"foo" ) as UTF-32. This in analogy with u8 literals (which are now char8_t literals), and which have already been required to be valid UTF-8. P0668R5, P0735R1, P0982R1 Revising the memory model The memory model has been revised. P0306R4, P1042R1 Enhancements of variadic macros Variadic macros are now allowed to be invoked with zero variadic arguments (this was previously accepted as an extension by many compilers). Within a variadic macros, the new feature __VA_OPT__(content) can now be used, which expands to nothing if there are no variadic arguments, and to content otherwise. A typical use case is for a comma that is required if and only if there are variadic arguments: define F(A, B, ...) vfunc(A, B __VA_OPT__(,) __VA_ARGS__) P0614R1 Range-based for statements with initializer A range-based for statement may now contain an additional initializer: for (Data d = FetchData(); const Row& row : d.rows()) { use(row); } P0683R1 Default member initializers for bit-fields Bit-fields can now have default member initializers: struct X { int a : 2 {-2}; int b : 2 = 1; }; P0960R3, P1975R0 Aggregate initialization from a parenthesized list Aggregates can now be initialized with round parentheses instead of curly braces: struct T { int a, b, c; }; T x(1, 2); A (motivating) consequence is that make_unique and emplace now work with aggregate types. P0428R2 Template head for generic lambdas A generic lambda may now use a template head instead of (and in addition to) auto parameters, e.g.: []<typename T>(T a, T& b, const T& c) {} P0624R2 Default-constructible and assignable stateless lambdas Objects of stateless closure type (i.e. the type of a lambda without any captures) can now be default-constructed and assigned. This allows uses such as lambdas as container predicates. P0315R4 Lambdas in unevaluated contexts Lambdas may now appear in unevaluated contexts (e.g. using F = decltype([](int a, int b) { return a + b; }); ). Combined with the above P0624R2, this makes lambdas usable in a wider range of situations. P0780R2, P2095R0, Pack expansion in lambda init-capture An init-capture may now introduce a pack: template <typename ...Args> void f(Args... args) { auto x = [...brgs = std::move(args)](){}; } P0409R2 Lambda capture [=, this] It is now allowed to spell the lambda capture [=, this] explicitly. Previously, the “ this ” was considered redundant and forbidden. See also P0806R2 above. P0961R1, P0969R0, P1091R3, P1381R1 Improvements for structured bindings P0961R1 and P0969R0 are intended as a defect resolution against C++17. P1009R2 Array size deduction in new-expressions This allows new int[]{1, 2, 3} , which was previously ill-formed. This change is intended as a defect resolution against C++17. P0702R1, P0739R0, P1814R0, P1816R0, P2082R1 Class template argument deduction (“CTAD”) Various tweaks and improvements. Some of these are defect resolutions against C++17 (P0702R1, P0739R0). Aliases and aggregate templates can now use CTAD. P1825R0 Copy elision and move semantics Rvalue reference variables can now be moved implicitly in return statements. This change is intended as a defect resolution against C++17. P0634R3 Fewer required typename disambiguations This change removes the need to disambiguate a dependent name as a typename via the typename keyword from several places where this is already unambiguous. This removes some redundant ceremony from template code. P0846R0 ADL and function templates that are not visible This change fixes a long-standing, somewhat obscure situation, where it was not possible to provide explicit template arguments for a function template that is meant to be found through ADL when the name was not known to refer to a function template. For example, f<A>(a) would have been treated as a binary expression f < A rather than as a template name f<A> . Previously, work-arounds were required to make ADL work in such a situation. P0692R1 Access checking on specializations This change fixes a long-standing, somewhat obscure situation, where it was not possible to declare a template specialization for a template argument that is a private (or protected) member type. For example, given class Foo { class Bar {}; }; , the access Foo::Bar is now allowed in template<class> struct X; template<> struct X<Foo::Bar>; . P0892R2 explicit(bool) The explicit specifier now accepts an optional boolean parameter (where explicit(true) is equivalent to explicit and explicit(false) is equivalent to the absence of explicit ), which simplifies generic code where explicitness is “forwarded” from template parameters in some sense. P1301R4 An optional string for [[nodiscard]] A new form of the attribute now allows specifying a text (e.g. guidance for a user who is erroneously discarding a result), e.g. [[nodiscard("did you mean to call a different function")]] . P0848R3 Conditionally trivial special member functions It is now possible to provide special member functions in both defaulted and non-defaulted forms at once, provided the declarations are constrained in a mutually exclusive way. This simplifies generic code where defaultedness is “forwarded” from template parameters in some sense. P1094R2 Nested inline namespaces Inline namespaces may now appear inside a nested namespace declaration: namespace a::inline b::c {} P1002R1, P1064R0, P1327R1, P1330R0, P1331R2, P1668R1 constexpr in the core language Additional core language facilities are now allowed in constexpr functions: try / catch , virtual function calls, dynamic_cast / typeid , changing the active union member, trivial default initialization, asm-definitions. P0202R3, P0415R1, P0858R0, P0879R0, P0972R0, P0980R1, P1004R2, P1006R1, P1065R2, P1023R0, P1032R1, P1424R1, P1645R1 constexpr in the library Many more library functions (including member functions) are now constexpr : algorithms, utilities, complex , swap , chrono , string , vector , pointer_traits , INVOKE , array comparisons, pair / tuple , numeric algorithms. There is also a new notion of a constexpr iterator. P0600R1 nodiscard in the library Several library (member) functions are now annotated with the [[nodiscard]] attribute (for example, vector::empty ). P0935R0 Remove accidentally- explicit default constructors This large change replaces many explicit constructors that have default arguments, such as explicit foo(Alloc a = Alloc()); , with two overloads, such that the resulting default constructor is not explicit. Previously, the one-parameter constructor was a default constructor, but because it was explicit, reasonable initializations such as foo x = {}; had been ill-formed. This was unintended, since explicit was only meant to inhibit implicit conversions. P0919R3, P1690R1 Heterogeneous lookup for unordered containers Analogous to heterogeneous lookup for ordered containers in C++14, this change allows transparent predicates to be defined and used in unordered containers. For example, an unordered_map with key string that uses transparent predicates can look up a string_view or a const char* without constructing a string object for the lookup. The details are more complicated than for ordered containers, since equality and hashing need to be compatible even when the types differ. P0458R2 Element existence in associative containers (“ contains ”) A new member function, m.contains(key) , equivalent to m.find(key) != m.end() , for all associative containers. P0646R1 Return element counts from list , forward_list operations The modifying member functions remove , remove_if and unique of list and forward_list now return the number of removed elements. P0457R2 Prefix/suffix checking for strings The class templates basic_string_view and basic_string have new member functions starts_with and ends_with that test whether the string starts/ends with the given prefix/suffix (string or single character). P0674R1 make_shared for arrays The make_shared creation function can now be used for array types, e.g: make_shared<T[]>(N); (Array types are supported by shared_ptr since C++17.) P0020R6 Floating-point atomic atomic<float> , atomic<double> , atomic<long double> P0718R2 Atomic shared_ptr and weak_ptr There are now partial specializations atomic<shared_ptr<T>> and atomic<weak_ptr<T>> that allow atomic access to a shared or weak pointer. This replaces the existing free function overloads shared_ptr<T> atomic_load(const shared_ptr<T>*) etc., which were fragile and error-prone. The old free function overloads are now deprecated. P0528R3, P1123R0 Atomic compare-and-exchange in the presence of padding This change makes it a requirement that compare-and-exchange for an atomic type atomic<T> works even when the type T contains padding bits. That is, whether the expected value equals the current value is no longer allowed to depend on unspecified padding; implementations may need to do extra work to make this happen (e.g. always store a predictable bit pattern in the padding, or use a masked comparison). P0439R0 Make memory_order a scoped enumeration Instead of std::memory_order_relaxed we now have std::memory_order::relaxed , etc.. The old names are provided as free constants for compatibility. P0616R0 Use std::move in <numeric> algorithms Algorithms such as accumulate used to be specified as having the binary operation called like acc = op(acc, *it) . This has now changed to acc = op(std::move(acc), *it) . P0408R7 Efficient access to the buffer of basic_stringbuf API additions to basic_stringbuf and string-stream classes that allow moving the buffering string in and out. P1148R0 Comprehensive review of [strings] A thorough cleanup of the specification of char_traits , basic_string_view , and basic_string . This resolves numerous LWG issues.

Miscellaneous

Document Summary Examples, notes P0941R2, P1353R0, P1902R1 Feature test macros Feature test macros are now part of the working paper. This is not relevant to the published International Standard, but it enables vendors to support upcoming language revisions incrementally and inform users which features are provided by the implementation. The feature test macros were previously maintained in the separate SD-6. P0754R2 The <version> header The new header <version> is provided. It is formally empty and not relevant to the published International Standard, but it provides a standardized place for implementation-defined information. Previously, the now-removed header <ciso646> (see P0619R4 above) was frequently and informally used for this purpose. The new feature test macros (see P0941R2 above) are defined in this header (as well as in their contextually appropriate place). P0788R3; P1458R1, P1459R1, P1460R1, P1462R1, P1463R1, P1464R1, P1622R3, P1686R2, P1718R2, P1719R2, P1720R2, P1721R2, P1722R2, P1723R2, P2045R1. Replace Requires with Constraints, Mandates, Preconditions in the specification A change to the formal specification of the library only: the old Requires element, which was serving multiple roles, is now obsolete and replaced by three new elements, Constraints (statically checked, affects overload resolution), Expects (preconditions whose violation results in undefined behaviour), and Mandates (statically checked conditions whose violation makes the program ill-formed). This should not have any observable effect, but it makes it clearer which requirements are diagnosed, which are the user’s responsibility, and which affect overload resolution (but do not produce errors per se). P0551R3 Restrict use of std functions and function templates A significant restriction in what users are allowed to do with standard library functions and function templates: Users are no longer allowed to specialize standard library function templates, and in general to take the address of a standard library function (unless the function is explicitly specified as addressable). This improves implementer freedom greatly to, say, implement a function as an overload set or a template. It marks a significant clarification of policy: functions in the standard library are in general only supposed to be understood as valid call expressions, not literally as declared functions. P1025R1 Update reference to Unicode Adds an undated reference to ISO/IEC 10646, and replaces “UCS4” with ”UTF-32“.

Unlisted papers

The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: P0339R6, P0340R3, P0357R3, P0388R4, P0475R1, P0487R1, P0602R4, P0608R3, P0641R2, P0655R1, P0704R1, P0738R2, P0759R1, P0771R1, P0809R0, P0883R2, P0899R1, P1008R1, P1131R2, P1139R2, P1165R1, P1207R4, P1285R0, P1522R1, P1638R1, P1908R1, P1960R0, P1961R0, P1963R0, P1965R0, P2101R0 . Additionally, the following otherwise unlisted papers were accepted as defect resolutions against C++17: P0588R1, P0593R6, P0682R1, P0727R0, P0859R0, P0929R2, P0962R1, P1164R1, P1286R2, P1771R1, P1957R2 .

The following papers contain issues that have been accepted as defect reports. CWG issues are handled by P0710R1, P0711R0, P0817R0, P0818R1, P0968R0, P1113R0, P1114R0, P1350R0, P1358R0, P1359R0, P1510R0, P1969R0, P1968R0, P1971R0, P2103R0, P2108R0 . LWG issues are handled by P0698R0, P0699R0, P0815R0, P0864R0, P0888R0, P1003R0, P1082R0, P1224R0, P1457R0, P1724R0, P1917R0, P2051R0, P2117R0 . Only specific issues may have been selected from each paper; the meeting minutes contain the details. The complete accumulation of accepted issues is published in the regularly updated CWG issues list and LWG issues list.

Defects, issues, bug fixes

The committee maintains a list of issues (see links above) which contain suggestions for improvements in the normative wording (clarifications, simplifications, corrections, etc.). When an issue is accepted that affects the published standard (not just the new work in progress), we have a defect report. The complete specification of C++ consists of the latest published document as amended by the resolutions of all subsequent defect reports. The resolution of a defect report is also incorporated into the working paper (as applicable), and thus the next published revision of the Standard no longer has that particular issue.

Therefore, the answer to the question of, say, “what is a valid C++14 program?” changes over time, up until the publication of C++17, and so forth. In practice, the situation is a bit more complicated when compiler vendors offer conformance modes for specific language revisions (e.g. -std=c++11 , -std=c++17 ). Vendors may consider defect resolutions to apply to any historic revision that contains the defect (whereas ISO considers only the most recent publication as the Standard).

Papers that have been applied to the working draft since the publication of C++20 and that are intended as defect reports are annotated with “DR” in the above change summary. Defect reports against C++20 that concern older (pre-C++20) content are not called out here specifically, nor are defects against C++17 whose resolutions are included in C++20. The full history of accepted issues together with the Standard revisions to which they apply is implicit in the CWG and LWG issues lists, but it is difficult to present explicitly.

Assorted snippets demonstrating C++20

int main() {}