Annex C (informative) Compatibility [diff]

C.1 C++ and ISO C++ 2023 [diff.cpp23]

C.1.1 General [diff.cpp23.general]

Subclause [diff.cpp23] lists the differences between C++ and ISO C++ 2023, by the chapters of this document.

C.1.2 [expr]: expressions [diff.cpp23.expr]

Affected subclause: [expr.arith.conv]
Change: Operations mixing a value of an enumeration type and a value of a different enumeration type or of a floating-point type are no longer valid.

Rationale: Reinforcing type safety.

Effect on original feature: A valid C++ 2023 program that performs operations mixing a value of an enumeration type and a value of a different enumeration type or of a floating-point type is ill-formed.
[Example 1: enum E1 { e }; enum E2 { f }; bool b = e <= 3.7; // ill-formed; previously well-formed int k = f - e; // ill-formed; previously well-formed auto x = true ? e : f; // ill-formed; previously well-formed — end example]
Affected subclauses: [expr.rel] and [expr.eq]
Change: Comparing two objects of array type is no longer valid.

Rationale: The old behavior was confusing since it compared not the contents of the two arrays, but their addresses.

Effect on original feature: A valid C++ 2023 program directly comparing two array objects is rejected as ill-formed in this document.
[Example 2: int arr1[5]; int arr2[5]; bool same = arr1 == arr2; // ill-formed; previously well-formed bool idem = arr1 == +arr2; // compare addresses bool less = arr1 < +arr2; // compare addresses, unspecified result — end example]
Affected subclause: [expr.delete]
Change: Calling delete on a pointer to an incomplete class is ill-formed.

Rationale: Reduce undefined behavior.

Effect on original feature: A valid C++ 2023 program that calls delete on an incomplete class type is ill-formed.
[Example 3: struct S; void f(S *p) { delete p; // ill-formed; previously well-formed } struct S {}; — end example]

C.1.3 [dcl.dcl]: declarations [diff.cpp23.dcl.dcl]

Affected subclause: [dcl.init.list]
Change: Pointer comparisons between initializer_list objects' backing arrays are unspecified.

Rationale: Permit the implementation to store backing arrays in static read-only memory.

Effect on original feature: Valid C++ 2023 code that relies on the result of pointer comparison between backing arrays may change behavior.
[Example 1: bool ne(std::initializer_list<int> a, std::initializer_list<int> b) { return a.begin() != b.begin() + 1; } bool b = ne({2,3}, {1,2,3}); // unspecified result; previously false — end example]
Affected subclause: [dcl.array]
Change: Previously, T...[n] would declare a pack of function parameters.
T...[n] is now a pack-index-specifier.

Rationale: Improve the handling of packs.

Effect on original feature: Valid C++ 2023 code that declares a pack of parameters without specifying a declarator-id becomes ill-formed.
[Example 2: template <typename... T> void f(T... [1]); template <typename... T> void g(T... ptr[1]); int main() { f<int, double>(nullptr, nullptr); // ill-formed, previously void f<int, double>(int [1], double [1]) g<int, double>(nullptr, nullptr); // ok } — end example]

C.1.4 [temp]: templates [diff.cpp23.temp]

Affected subclause: [temp.constr]
Change: Some atomic constraints become fold expanded constraints.

Rationale: Permit the subsumption of fold expressions.

Effect on original feature: Valid C++ 2023 code may become ill-formed.
[Example 1: template <typename ...V> struct A; struct S { static constexpr int compare(const S&) { return 1; } }; template <typename ...T, typename ...U> void f(A<T ...> *, A<U ...> *) requires (T::compare(U{}) && ...); // was well-formed (atomic constraint of type bool), // now ill-formed (results in an atomic constraint of type int) void g(A<S, S> *ap) { f(ap, ap); } — end example]
Affected subclause: [temp.deduct.call]
Change: Template argument deduction from overload sets succeeds in more cases.

Rationale: Allow consideration of constraints to disambiguate overload sets used as parameters in function calls.

Effect on original feature: Valid C++ 2023 code may become ill-formed.
[Example 2: template <typename T> void f(T &&, void (*)(T &&)); void g(int &); // #1 inline namespace A { void g(short &&); // #2 } inline namespace B { void g(short &&); // #3 } void q() { int x; f(x, g); // ill-formed; previously well-formed, deducing T = int& }
There is no change to the applicable deduction rules for the individual g candidates: Type deduction from #1 does not succeed; type deductions from #2 and #3 both succeed.
— end example]

C.1.5 [library]: library introduction [diff.cpp23.library]

Affected subclause: [headers]
Change: New headers.

Rationale: New functionality.

Effect on original feature: The following C++ headers are new: <debugging>, <hazard_pointer>, <inplace_vector>, <linalg>, <rcu>, <simd>, and <text_encoding>.
Valid C++ 2023 code that #includes headers with these names may be invalid in this revision of C++.

C.1.6 [strings]: strings library [diff.cpp23.strings]

Affected subclause: [string.conversions]
Change: Output of floating-point overloads of to_string and to_wstring.

Rationale: Prevent loss of information and improve consistency with other formatting facilities.

Effect on original feature: to_string and to_wstring function calls that take floating-point arguments may produce a different output.
[Example 1: auto s = std::to_string(1e-7); // "1e-07" // previously "0.000000" with '.' possibly // changed according to the global C locale — end example]

C.1.7 [containers]: containers library [diff.cpp23.containers]

Affected subclause: [span.overview]
Change: span<const T> is constructible from initializer_list<T>.

Rationale: Permit passing a braced initializer list to a function taking span.

Effect on original feature: Valid C++ 2023 code that relies on the lack of this constructor may refuse to compile, or change behavior in this revision of C++.
[Example 1: void one(pair<int, int>); // #1 void one(span<const int>); // #2 void t1() { one({1, 2}); } // ambiguous between #1 and #2; previously called #1 void two(span<const int, 2>); void t2() { two({{1, 2}}); } // ill-formed; previously well-formed void *a[10]; int x = span<void* const>{a, 0}.size(); // x is 2; previously 0 any b[10]; int y = span<const any>{b, b + 10}.size(); // y is 2; previously 10 — end example]

C.1.8 [depr]: compatibility features [diff.cpp23.depr]

Change: Remove the type alias allocator<T>​::​is_always_equal.

Rationale: Non-empty allocator classes derived from allocator needed to explicitly define an is_always_equal member type so that allocator_traits would not use the one from the allocator base class.

Effect on original feature: It is simpler to correctly define an allocator class with an allocator base class.
[Example 1: template <class T> struct MyAlloc : allocator<T> { int tag; }; static_assert(!allocator_traits<MyAlloc<int>>::is_always_equal); // Error in C++ 2023, // OK in C++ 2026 — end example]
Change: Removal of atomic access API for shared_ptr objects.

Rationale: The old behavior was brittle.
shared_ptr objects using the old API were not protected by the type system, and certain interactions with code not using this API would, in some cases, silently produce undefined behavior.
A complete type-safe replacement is provided in the form of atomic<shared_ptr<T>>.

Effect on original feature: A valid C++ 2023 program that relies on the presence of the removed functions may fail to compile.
Change: Remove the basic_string​::​reserve() overload with no parameters.

Rationale: The overload of reserve with no parameters is redundant.
The shrink_to_fit member function can be used instead.

Effect on original feature: A valid C++ 2023 program that calls reserve() on a basic_string object may fail to compile.
The old functionality can be achieved by calling shrink_to_fit() instead, or the function call can be safely eliminated with no side effects.
Change: Remove header <codecvt> and all its contents.

Rationale: The header has been deprecated for the previous three editions of this document and no longer implements the current Unicode standard, supporting only the obsolete UCS-2 encoding.
Ongoing support is at implementer's discretion, exercising freedoms granted by [zombie.names].

Effect on original feature: A valid C++ 2023 program #include-ing the header or importing the header unit may fail to compile.
Code that uses any of the following names by importing the standard library modules may fail to compile:
Change: Remove header <strstream> and all its contents.

Rationale: The header has been deprecated since the original C++ standard; the <spanstream> header provides an updated, safer facility.
Ongoing support is at implementer's discretion, exercising freedoms granted by [zombie.names].

Effect on original feature: A valid C++ 2023 program #include-ing the header or importing the header unit may become ill-formed.
Code that uses any of the following classes by importing one of the standard library modules may become ill-formed:
Change: Remove convenience interfaces wstring_convert and wbuffer_convert.

Rationale: These features were underspecified with no clear error reporting mechanism and were deprecated for the last three editions of this document.
Ongoing support is at implementer's discretion, exercising freedoms granted by [zombie.names].

Effect on original feature: A valid C++ 2023 program using these interfaces may become ill-formed.

C.2 C++ and ISO C++ 2020 [diff.cpp20]

C.2.1 General [diff.cpp20.general]

Subclause [diff.cpp20] lists the differences between C++ and ISO C++ 2020, in addition to those listed above, by the chapters of this document.

C.2.2 [lex]: lexical conventions [diff.cpp20.lex]

Affected subclause: [lex.name]
Change: Previously valid identifiers containing characters not present in UAX #44 properties XID_Start or XID_Continue, or not in Normalization Form C, are now rejected.

Rationale: Prevent confusing characters in identifiers.
Requiring normalization of names ensures consistent linker behavior.

Effect on original feature: Some identifiers are no longer well-formed.
Affected subclause: [lex.string]
Change: Concatenated string-literals can no longer have conflicting encoding-prefixes.

Rationale: Removal of unimplemented conditionally-supported feature.

Effect on original feature: Concatenation of string-literals with different encoding-prefixes is now ill-formed.
[Example 1: auto c = L"a" U"b"; // was conditionally-supported; now ill-formed — end example]

C.2.3 [expr]: expressions [diff.cpp20.expr]

Affected subclause: [expr.prim.id.unqual]
Change: Change move-eligible id-expressions from lvalues to xvalues.

Rationale: Simplify the rules for implicit move.

Effect on original feature: Valid C++ 2020 code that relies on a returned id-expression's being an lvalue may change behavior or fail to compile.
[Example 1: decltype(auto) f(int&& x) { return (x); } // returns int&&; previously returned int& int& g(int&& x) { return x; } // ill-formed; previously well-formed — end example]
Affected subclause: [expr.sub]
Change: Change the meaning of comma in subscript expressions.

Rationale: Enable repurposing a deprecated syntax to support multidimensional indexing.

Effect on original feature: Valid C++ 2020 code that uses a comma expression within a subscript expression may fail to compile.
[Example 2: arr[1, 2] // was equivalent to arr[(1, 2)], // now equivalent to arr.operator[](1, 2) or ill-formed — end example]

C.2.4 [stmt.stmt]: statements [diff.cpp20.stmt]

Affected subclause: [stmt.ranged]
Change: The lifetime of temporary objects in the for-range-initializer is extended until the end of the loop ([class.temporary]).

Rationale: Improve usability of the range-based for statement.

Effect on original feature: Destructors of some temporary objects are invoked later.
[Example 1: void f() { std::vector<int> v = { 42, 17, 13 }; std::mutex m; for (int x : static_cast<void>(std::lock_guard<std::mutex>(m)), v) { // lock released in C++ 2020 std::lock_guard<std::mutex> guard(m); // OK in C++ 2020, now deadlocks } } — end example]

C.2.5 [dcl.dcl]: declarations [diff.cpp20.dcl]

Affected subclause: [dcl.init.string]
Change: UTF-8 string literals may initialize arrays of char or unsigned char.

Rationale: Compatibility with previously written code that conformed to previous versions of this document.

Effect on original feature: Arrays of char or unsigned char may now be initialized with a UTF-8 string literal.
This can affect initialization that includes arrays that are directly initialized within class types, typically aggregates.
[Example 1: struct A { char8_t s[10]; }; struct B { char s[10]; }; void f(A); void f(B); int main() { f({u8""}); // ambiguous } — end example]

C.2.6 [temp]: templates [diff.cpp20.temp]

Affected subclause: [temp.deduct.type]
Change: Deducing template arguments from exception specifications.

Rationale: Facilitate generic handling of throwing and non-throwing functions.

Effect on original feature: Valid ISO C++ 2020 code may be ill-formed in this revision of C++.
[Example 1: template<bool> struct A { }; template<bool B> void f(void (*)(A<B>) noexcept(B)); void g(A<false>) noexcept; void h() { f(g); // ill-formed; previously well-formed } — end example]

C.2.7 [library]: library introduction [diff.cpp20.library]

Affected subclause: [headers]
Change: New headers.

Rationale: New functionality.

Effect on original feature: The following C++ headers are new: <expected>, <flat_map>, <flat_set>, <generator>, <mdspan>, <print>, <spanstream>, <stacktrace>, <stdatomic.h>, and <stdfloat>.
Valid C++ 2020 code that #includes headers with these names may be invalid in this revision of C++.

C.2.8 [concepts]: concepts library [diff.cpp20.concepts]

Affected subclauses: [cmp.concept], [concept.equalitycomparable], and [concept.totallyordered]
Change: Replace common_reference_with in three_way_comparable_with, equality_comparable_with, and totally_ordered_with with an exposition-only concept.

Rationale: Allow uncopyable, but movable, types to model these concepts.

Effect on original feature: Valid C++ 2020 code relying on subsumption with common_reference_with may fail to compile in this revision of C++.
[Example 1: template<class T, class U> requires equality_comparable_with<T, U> bool attempted_equals(const T&, const U& u); // previously selected overload template<class T, class U> requires common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> bool attempted_equals(const T& t, const U& u); // ambiguous overload; previously // rejected by partial ordering bool test(shared_ptr<int> p) { return attempted_equals(p, nullptr); // ill-formed; previously well-formed } — end example]

C.2.9 [mem]: memory management library [diff.cpp20.memory]

Affected subclause: [allocator.traits.general]
Change: Forbid partial and explicit program-defined specializations of allocator_traits.

Rationale: Allow addition of allocate_at_least to allocator_traits, and potentially other members in the future.

Effect on original feature: Valid C++ 2020 code that partially or explicitly specializes allocator_traits is ill-formed with no diagnostic required in this revision of C++.

C.2.10 [utilities]: general utilities library [diff.cpp20.utilities]

Affected subclause: [format]
Change: Signature changes: format, format_to, vformat_to, format_to_n, formatted_size.
Removal of format_args_t.

Rationale: Improve safety via compile-time format string checks, avoid unnecessary template instantiations.

Effect on original feature: Valid C++ 2020 code that contained errors in format strings or relied on previous format string signatures or format_args_t may become ill-formed.
[Example 1: auto s = std::format("{:d}", "I am not a number"); // ill-formed, // previously threw format_error — end example]
Affected subclause: [format]
Change: Signature changes: format, format_to, format_to_n, formatted_size.

Rationale: Enable formatting of views that do not support iteration when const-qualified and that are not copyable.

Effect on original feature: Valid C++ 2020 code that passes bit-fields to formatting functions may become ill-formed.
[Example 2: struct tiny { int bit: 1; }; auto t = tiny(); std::format("{}", t.bit); // ill-formed, previously returned "0" — end example]
Affected subclause: [format.string.std]
Change: Restrict types of formatting arguments used as width or precision in a std-format-spec.

Rationale: Disallow types that do not have useful or portable semantics as a formatting width or precision.

Effect on original feature: Valid C++ 2020 code that passes a boolean or character type as arg-id becomes invalid.
[Example 3: std::format("{:*^{}}", "", true); // ill-formed, previously returned "*" std::format("{:*^{}}", "", '1'); // ill-formed, previously returned an // implementation-defined number of '*' characters — end example]
Affected subclause: [format.formatter.spec]
Change: Removed the formatter specialization: template<size_t N> struct formatter<const charT[N], charT>;
Rationale: The specialization is inconsistent with the design of formatter, which is intended to be instantiated only with cv-unqualified object types.

Effect on original feature: Valid C++ 2020 code that instantiated the removed specialization can become ill-formed.

C.2.11 [strings]: strings library [diff.cpp20.strings]

Affected subclause: [string.classes]
Change: Additional rvalue overload for the substr member function and the corresponding constructor.

Rationale: Improve efficiency of operations on rvalues.

Effect on original feature: Valid C++ 2020 code that created a substring by calling substr (or the corresponding constructor) on an xvalue expression with type S that is a specialization of basic_string may change meaning in this revision of C++.
[Example 1: std::string s1 = "some long string that forces allocation", s2 = s1; std::move(s1).substr(10, 5); assert(s1 == s2); // unspecified, previously guaranteed to be true std::string s3(std::move(s2), 10, 5); assert(s1 == s2); // unspecified, previously guaranteed to be true — end example]

C.2.12 [containers]: containers library [diff.cpp20.containers]

Affected subclauses: [associative.reqmts] and [unord.req]
Change: Heterogeneous extract and erase overloads for associative containers.

Rationale: Improve efficiency of erasing elements from associative containers.

Effect on original feature: Valid C++ 2020 code may fail to compile in this revision of C++.
[Example 1: struct B { auto operator<=>(const B&) const = default; }; struct D : private B { void f(std::set<B, std::less<>>& s) { s.erase(*this); // ill-formed; previously well-formed } }; — end example]

C.2.13 [thread]: concurrency support library [diff.cpp20.thread]

Affected subclause: [thread.barrier]
Change: In this revision of C++, it is implementation-defined whether a barrier's phase completion step runs if no thread calls wait.
Previously the phase completion step was guaranteed to run on the last thread that calls arrive or arrive_and_drop during the phase.
In this revision of C++, it can run on any of the threads that arrived or waited at the barrier during the phase.

Rationale: Correct contradictory wording and improve implementation flexibility for performance.

Effect on original feature: Valid C++ 2020 code using a barrier might have different semantics in this revision of C++ if it depends on a completion function's side effects occurring exactly once, on a specific thread running the phase completion step, or on a completion function's side effects occurring without wait having been called.
[Example 1: auto b0 = std::barrier(1); b0.arrive(); b0.arrive(); // implementation-defined; previously well-defined int data = 0; auto b1 = std::barrier(1, [&] { data++; }); b1.arrive(); assert(data == 1); // implementation-defined; previously well-defined b1.arrive(); // implementation-defined; previously well-defined — end example]

C.3 C++ and ISO C++ 2017 [diff.cpp17]

C.3.1 General [diff.cpp17.general]

Subclause [diff.cpp17] lists the differences between C++ and ISO C++ 2017, in addition to those listed above, by the chapters of this document.

C.3.2 [lex]: lexical conventions [diff.cpp17.lex]

Affected subclauses: [lex.pptoken], [module.unit], [module.import], [cpp.pre], [cpp.module], and [cpp.import]
Change: New identifiers with special meaning.

Rationale: Required for new features.

Effect on original feature: Logical lines beginning with module or import may be interpreted differently in this revision of C++.
[Example 1: class module {}; module m1; // was variable declaration; now module-declaration module *m2; // variable declaration class import {}; import j1; // was variable declaration; now module-import-declaration ::import j2; // variable declaration — end example]
Affected subclause: [lex.header]
Change: header-name tokens are formed in more contexts.

Rationale: Required for new features.

Effect on original feature: When the identifier import is followed by a < character, a header-name token may be formed.
[Example 2: template<typename> class import {}; import<int> f(); // ill-formed; previously well-formed ::import<int> g(); // OK — end example]
Affected subclause: [lex.key]
Change: New keywords.

Rationale: Required for new features.
Effect on original feature: Valid C++ 2017 code using char8_t, concept, consteval, constinit, co_await, co_yield, co_return, or requires as an identifier is not valid in this revision of C++.
Affected subclause: [lex.operators]
Change: New operator <=>.

Rationale: Necessary for new functionality.

Effect on original feature: Valid C++ 2017 code that contains a <= token immediately followed by a > token may be ill-formed or have different semantics in this revision of C++.
[Example 3: namespace N { struct X {}; bool operator<=(X, X); template<bool(X, X)> struct Y {}; Y<operator<=> y; // ill-formed; previously well-formed } — end example]
Affected subclause: [lex.literal]
Change: Type of UTF-8 string and character literals.

Rationale: Required for new features.
The changed types enable function overloading, template specialization, and type deduction to distinguish ordinary and UTF-8 string and character literals.

Effect on original feature: Valid C++ 2017 code that depends on UTF-8 string literals having type “array of const char” and UTF-8 character literals having type “char” is not valid in this revision of C++.
[Example 4: const auto *u8s = u8"text"; // u8s previously deduced as const char*; now deduced as const char8_t* const char *ps = u8s; // ill-formed; previously well-formed auto u8c = u8'c'; // u8c previously deduced as char; now deduced as char8_t char *pc = &u8c; // ill-formed; previously well-formed std::string s = u8"text"; // ill-formed; previously well-formed void f(const char *s); f(u8"text"); // ill-formed; previously well-formed template<typename> struct ct; template<> struct ct<char> { using type = char; }; ct<decltype(u8'c')>::type x; // ill-formed; previously well-formed. — end example]

C.3.3 [basic]: basics [diff.cpp17.basic]

Affected subclause: [basic.life]
Change: A pseudo-destructor call ends the lifetime of the object to which it is applied.

Rationale: Increase consistency of the language model.

Effect on original feature: Valid ISO C++ 2017 code may be ill-formed or have undefined behavior in this revision of C++.
[Example 1: int f() { int a = 123; using T = int; a.~T(); return a; // undefined behavior; previously returned 123 } — end example]
Affected subclause: [intro.races]
Change: Except for the initial release operation, a release sequence consists solely of atomic read-modify-write operations.

Rationale: Removal of rarely used and confusing feature.

Effect on original feature: If a memory_order_release atomic store is followed by a memory_order_relaxed store to the same variable by the same thread, then reading the latter value with a memory_order_acquire load no longer provides any “happens before” guarantees, even in the absence of intervening stores by another thread.

C.3.4 [expr]: expressions [diff.cpp17.expr]

Affected subclause: [expr.prim.lambda.capture]
Change: Implicit lambda capture may capture additional entities.

Rationale: Rule simplification, necessary to resolve interactions with constexpr if.

Effect on original feature: Lambdas with a capture-default may capture local entities that were not captured in C++ 2017 if those entities are only referenced in contexts that do not result in an odr-use.

C.3.5 [dcl.dcl]: declarations [diff.cpp17.dcl.dcl]

Affected subclause: [dcl.typedef]
Change: Unnamed classes with a typedef name for linkage purposes can contain only C-compatible constructs.

Rationale: Necessary for implementability.

Effect on original feature: Valid C++ 2017 code may be ill-formed in this revision of C++.
[Example 1: typedef struct { void f() {} // ill-formed; previously well-formed } S; — end example]
Affected subclause: [dcl.fct.default]
Change: A function cannot have different default arguments in different translation units.

Rationale: Required for modules support.

Effect on original feature: Valid C++ 2017 code may be ill-formed in this revision of C++, with no diagnostic required.
[Example 2: // Translation unit 1 int f(int a = 42); int g() { return f(); } // Translation unit 2 int f(int a = 76) { return a; } // ill-formed, no diagnostic required; previously well-formed int g(); int main() { return g(); } // used to return 42 — end example]
Affected subclause: [dcl.init.aggr]
Change: A class that has user-declared constructors is never an aggregate.

Rationale: Remove potentially error-prone aggregate initialization which may apply notwithstanding the declared constructors of a class.

Effect on original feature: Valid C++ 2017 code that aggregate-initializes a type with a user-declared constructor may be ill-formed or have different semantics in this revision of C++.
[Example 3: struct A { // not an aggregate; previously an aggregate A() = delete; }; struct B { // not an aggregate; previously an aggregate B() = default; int i = 0; }; struct C { // not an aggregate; previously an aggregate C(C&&) = default; int a, b; }; A a{}; // ill-formed; previously well-formed B b = {1}; // ill-formed; previously well-formed auto* c = new C{2, 3}; // ill-formed; previously well-formed struct Y; struct X { operator Y(); }; struct Y { // not an aggregate; previously an aggregate Y(const Y&) = default; X x; }; Y y{X{}}; // copy constructor call; previously aggregate-initialization — end example]
Affected subclause: [dcl.init.list]
Change: Boolean conversion from a pointer or pointer-to-member type is now a narrowing conversion.

Rationale: Catches bugs.

Effect on original feature: Valid C++ 2017 code may fail to compile in this revision of C++.
[Example 4: bool y[] = { "bc" }; // ill-formed; previously well-formed — end example]

C.3.6 [class]: classes [diff.cpp17.class]

Affected subclauses: [class.ctor] and [class.conv.fct]
Change: The class name can no longer be used parenthesized immediately after an explicit decl-specifier in a constructor declaration.
The conversion-function-id can no longer be used parenthesized immediately after an explicit decl-specifier in a conversion function declaration.

Rationale: Necessary for new functionality.

Effect on original feature: Valid C++ 2017 code may fail to compile in this revision of C++.
[Example 1: struct S { explicit (S)(const S&); // ill-formed; previously well-formed explicit (operator int)(); // ill-formed; previously well-formed explicit(true) (S)(int); // OK }; — end example]
Affected subclauses: [class.ctor] and [class.dtor]
Change: A simple-template-id is no longer valid as the declarator-id of a constructor or destructor.

Rationale: Remove potentially error-prone option for redundancy.

Effect on original feature: Valid C++ 2017 code may fail to compile in this revision of C++.
[Example 2: template<class T> struct A { A<T>(); // error: simple-template-id not allowed for constructor A(int); // OK, injected-class-name used ~A<T>(); // error: simple-template-id not allowed for destructor }; — end example]
Affected subclause: [class.copy.elision]
Change: A function returning an implicitly movable entity may invoke a constructor taking an rvalue reference to a type different from that of the returned expression.
Function and catch-clause parameters can be thrown using move constructors.

Rationale: Side effect of making it easier to write more efficient code that takes advantage of moves.

Effect on original feature: Valid C++ 2017 code may fail to compile or have different semantics in this revision of C++.
[Example 3: struct base { base(); base(base const &); private: base(base &&); }; struct derived : base {}; base f(base b) { throw b; // error: base(base &&) is private derived d; return d; // error: base(base &&) is private } struct S { S(const char *s) : m(s) { } S(const S&) = default; S(S&& other) : m(other.m) { other.m = nullptr; } const char * m; }; S consume(S&& s) { return s; } void g() { S s("text"); consume(static_cast<S&&>(s)); char c = *s.m; // undefined behavior; previously ok } — end example]

C.3.7 [over]: overloading [diff.cpp17.over]

Affected subclause: [over.match.oper]
Change: Equality and inequality expressions can now find reversed and rewritten candidates.

Rationale: Improve consistency of equality with three-way comparison and make it easier to write the full complement of equality operations.

Effect on original feature: For certain pairs of types where one is convertible to the other, equality or inequality expressions between an object of one type and an object of the other type invoke a different operator.
Also, for certain types, equality or inequality expressions between two objects of that type become ambiguous.
[Example 1: struct A { operator int() const; }; bool operator==(A, int); // #1 // #2 is built-in candidate: bool operator==(int, int); // #3 is built-in candidate: bool operator!=(int, int); int check(A x, A y) { return (x == y) + // ill-formed; previously well-formed (10 == x) + // calls #1, previously selected #2 (10 != x); // calls #1, previously selected #3 } — end example]
Affected subclause: [over.match.oper]
Change: Overload resolution may change for equality operators ([expr.eq]).

Rationale: Support calling operator== with reversed order of arguments.

Effect on original feature: Valid C++ 2017 code that uses equality operators with conversion functions may be ill-formed or have different semantics in this revision of C++.
[Example 2: struct A { operator int() const { return 10; } }; bool operator==(A, int); // #1 // #2 is built-in candidate: bool operator==(int, int); bool b = 10 == A(); // calls #1 with reversed order of arguments; previously selected #2 struct B { bool operator==(const B&); // member function with no cv-qualifier }; B b1; bool eq = (b1 == b1); // ambiguous; previously well-formed — end example]

C.3.8 [temp]: templates [diff.cpp17.temp]

Affected subclause: [temp.names]
Change: An unqualified-id that is followed by a < and for which name lookup finds nothing or finds a function will be treated as a template-name in order to potentially cause argument-dependent lookup to be performed.

Rationale: It was problematic to call a function template with an explicit template argument list via argument-dependent lookup because of the need to have a template with the same name visible via normal lookup.

Effect on original feature: Previously valid code that uses a function name as the left operand of a < operator would become ill-formed.
[Example 1: struct A {}; bool operator<(void (*fp)(), A); void f() {} int main() { A a; f < a; // ill-formed; previously well-formed (f) < a; // still well-formed } — end example]

C.3.9 [except]: exception handling [diff.cpp17.except]

Affected subclause: [except.spec]
Change: Remove throw() exception specification.

Rationale: Removal of obsolete feature that has been replaced by noexcept.

Effect on original feature: A valid C++ 2017 function declaration, member function declaration, function pointer declaration, or function reference declaration that uses throw() for its exception specification will be rejected as ill-formed in this revision of C++.
It should simply be replaced with noexcept for no change of meaning since C++ 2017.
[Note 1: 
There is no way to write a function declaration that is non-throwing in this revision of C++ and is also non-throwing in C++ 2003 except by using the preprocessor to generate a different token sequence in each case.
— end note]

C.3.10 [library]: library introduction [diff.cpp17.library]

Affected subclause: [headers]
Change: New headers.

Rationale: New functionality.

Valid C++ 2017 code that #includes headers with these names may be invalid in this revision of C++.
Affected subclause: [headers]
Change: Remove vacuous C++ header files.

Rationale: The empty headers implied a false requirement to achieve C compatibility with the C++ headers.

Effect on original feature: A valid C++ 2017 program that #includes any of the following headers may fail to compile: <ccomplex>, <ciso646>, <cstdalign>, <cstdbool>, and <ctgmath>.
To retain the same behavior:
  • a #include of <ccomplex> can be replaced by a #include of <complex>,
  • a #include of <ctgmath> can be replaced by a #include of <cmath> and a #include of <complex>, and
  • a #include of <ciso646>, <cstdalign>, or <cstdbool> can simply be removed.

C.3.11 [containers]: containers library [diff.cpp17.containers]

Affected subclauses: [forward.list] and [list]
Change: Return types of remove, remove_if, and unique changed from void to container​::​size_type.

Rationale: Improve efficiency and convenience of finding number of removed elements.

Effect on original feature: Code that depends on the return types might have different semantics in this revision of C++.
Translation units compiled against this version of C++ may be incompatible with translation units compiled against C++ 2017, either failing to link or having undefined behavior.

C.3.12 [iterators]: iterators library [diff.cpp17.iterators]

Affected subclause: [iterator.traits]
Change: The specialization of iterator_traits for void* and for function pointer types no longer contains any nested typedefs.

Rationale: Corrects an issue misidentifying pointer types that are not incrementable as iterator types.

Effect on original feature: A valid C++ 2017 program that relies on the presence of the typedefs may fail to compile, or have different behavior.

C.3.13 [algorithms]: algorithms library [diff.cpp17.alg.reqs]

Affected subclause: [algorithms.requirements]
Change: The number and order of deducible template parameters for algorithm declarations is now unspecified, instead of being as-declared.

Rationale: Increase implementor freedom and allow some function templates to be implemented as function objects with templated call operators.

Effect on original feature: A valid C++ 2017 program that passes explicit template arguments to algorithms not explicitly specified to allow such in this version of C++ may fail to compile or have undefined behavior.

C.3.14 [input.output]: input/output library [diff.cpp17.input.output]

Affected subclause: [istream.extractors]
Change: Character array extraction only takes array types.

Rationale: Increase safety via preventing buffer overflow at compile time.

Effect on original feature: Valid C++ 2017 code may fail to compile in this revision of C++.
[Example 1: auto p = new char[100]; char q[100]; std::cin >> std::setw(20) >> p; // ill-formed; previously well-formed std::cin >> std::setw(20) >> q; // OK — end example]
Affected subclause: [ostream.inserters.character]
Change: Overload resolution for ostream inserters used with UTF-8 literals.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2017 code that passes UTF-8 literals to basic_ostream<char, ...>​::​operator<< or basic_ostream<wchar_t, ...>​::​operator<< is now ill-formed.
[Example 2: std::cout << u8"text"; // previously called operator<<(const char*) and printed a string; // now ill-formed std::cout << u8'X'; // previously called operator<<(char) and printed a character; // now ill-formed — end example]
Affected subclause: [ostream.inserters.character]
Change: Overload resolution for ostream inserters used with wchar_t, char16_t, or char32_t types.

Rationale: Removal of surprising behavior.

Effect on original feature: Valid C++ 2017 code that passes wchar_t, char16_t, or char32_t characters or strings to basic_ostream<char, ...>​::​operator<< or that passes char16_t or char32_t characters or strings to basic_ostream<wchar_t, ...>​::​operator<< is now ill-formed.
[Example 3: std::cout << u"text"; // previously formatted the string as a pointer value; // now ill-formed std::cout << u'X'; // previously formatted the character as an integer value; // now ill-formed — end example]
Affected subclause: [fs.class.path]
Change: Return type of filesystem path format observer member functions.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2017 code that depends on the u8string() and generic_u8string() member functions of std​::​filesystem​::​path returning std​::​string is not valid in this revision of C++.
[Example 4: std::filesystem::path p; std::string s1 = p.u8string(); // ill-formed; previously well-formed std::string s2 = p.generic_u8string(); // ill-formed; previously well-formed — end example]

C.3.15 [depr]: compatibility features [diff.cpp17.depr]

Change: Remove uncaught_exception.

Rationale: The function did not have a clear specification when multiple exceptions were active, and has been superseded by uncaught_exceptions.

Effect on original feature: A valid C++ 2017 program that calls std​::​uncaught_exception may fail to compile.
It can be revised to use std​::​uncaught_exceptions instead, for clear and portable semantics.
Change: Remove support for adaptable function API.
Rationale: The deprecated support relied on a limited convention that could not be extended to support the general case or new language features.
It has been superseded by direct language support with decltype, and by the std​::​bind and std​::​not_fn function templates.

Effect on original feature: A valid C++ 2017 program that relies on the presence of result_type, argument_type, first_argument_type, or second_argument_type in a standard library class may fail to compile.
A valid C++ 2017 program that calls not1 or not2, or uses the class templates unary_negate or binary_negate, may fail to compile.
Change: Remove redundant members from std​::​allocator.

Rationale: std​::​allocator was overspecified, encouraging direct usage in user containers rather than relying on std​::​allocator_traits, leading to poor containers.

Effect on original feature: A valid C++ 2017 program that directly makes use of the pointer, const_pointer, reference, const_reference, rebind, address, construct, destroy, or max_size members of std​::​allocator, or that directly calls allocate with an additional hint argument, may fail to compile.
Change: Remove raw_storage_iterator.

Rationale: The iterator encouraged use of potentially-throwing algorithms, but did not return the number of elements successfully constructed, as would be necessary to destroy them.

Effect on original feature: A valid C++ 2017 program that uses this iterator class may fail to compile.
Change: Remove temporary buffers API.
Rationale: The temporary buffer facility was intended to provide an efficient optimization for small memory requests, but there is little evidence this was achieved in practice, while requiring the user to provide their own exception-safe wrappers to guard use of the facility in many cases.

Effect on original feature: A valid C++ 2017 program that calls get_temporary_buffer or return_temporary_buffer may fail to compile.
Change: Remove shared_ptr​::​unique.

Rationale: The result of a call to this member function is not reliable in the presence of multiple threads and weak pointers.
The member function use_count is similarly unreliable, but has a clearer contract in such cases, and remains available for well-defined use in single-threaded cases.

Effect on original feature: A valid C++ 2017 program that calls unique on a shared_ptr object may fail to compile.
Affected subclause: [depr.meta.types]
Change: Remove deprecated type traits.

Rationale: The traits had unreliable or awkward interfaces.
The is_literal_type trait provided no way to detect which subset of constructors and member functions of a type were declared constexpr.
The result_of trait had a surprising syntax that did not directly support function types.
It has been superseded by the invoke_result trait.

Effect on original feature: A valid C++ 2017 program that relies on the is_literal_type or result_of type traits, on the is_literal_type_v variable template, or on the result_of_t alias template may fail to compile.

C.4 C++ and ISO C++ 2014 [diff.cpp14]

C.4.1 General [diff.cpp14.general]

Subclause [diff.cpp14] lists the differences between C++ and ISO C++ 2014, in addition to those listed above, by the chapters of this document.

C.4.2 [lex]: lexical conventions [diff.cpp14.lex]

Affected subclause: [lex.phases]
Change: Removal of trigraph support as a required feature.

Rationale: Prevents accidental uses of trigraphs in non-raw string literals and comments.

Effect on original feature: Valid C++ 2014 code that uses trigraphs may not be valid or may have different semantics in this revision of C++.
Implementations may choose to translate trigraphs as specified in C++ 2014 if they appear outside of a raw string literal, as part of the implementation-defined mapping from input source file characters to the translation character set.
Affected subclause: [lex.ppnumber]
Change: pp-number can contain p sign and P sign.

Rationale: Necessary to enable hexadecimal-floating-point-literals.

Effect on original feature: Valid C++ 2014 code may fail to compile or produce different results in this revision of C++.
Specifically, character sequences like 0p+0 and 0e1_p+0 are three separate tokens each in C++ 2014, but one single token in this revision of C++.
[Example 1: #define F(a) b ## a int b0p = F(0p+0); // ill-formed; equivalent to “int b0p = b0p + 0;'' in C++ 2014 — end example]

C.4.3 [expr]: expressions [diff.cpp14.expr]

Affected subclauses: [expr.post.incr] and [expr.pre.incr]
Change: Remove increment operator with bool operand.

Rationale: Obsolete feature with occasionally surprising semantics.

Effect on original feature: A valid C++ 2014 expression utilizing the increment operator on a bool lvalue is ill-formed in this revision of C++.
Affected subclauses: [expr.new] and [expr.delete]
Change: Dynamic allocation mechanism for over-aligned types.

Rationale: Simplify use of over-aligned types.

Effect on original feature: In C++ 2014 code that uses a new-expression to allocate an object with an over-aligned class type, where that class has no allocation functions of its own, ​::​operator new(std​::​size_t) is used to allocate the memory.
In this revision of C++, ​::​operator new(std​::​size_t, std​::​align_val_t) is used instead.

C.4.4 [dcl.dcl]: declarations [diff.cpp14.dcl.dcl]

Affected subclause: [dcl.stc]
Change: Removal of register storage-class-specifier.

Rationale: Enable repurposing of deprecated keyword in future revisions of C++.

Effect on original feature: A valid C++ 2014 declaration utilizing the register storage-class-specifier is ill-formed in this revision of C++.
The specifier can simply be removed to retain the original meaning.
Affected subclause: [dcl.spec.auto]
Change: auto deduction from braced-init-list.

Rationale: More intuitive deduction behavior.

Effect on original feature: Valid C++ 2014 code may fail to compile or may change meaning in this revision of C++.
[Example 1: auto x1{1}; // was std​::​initializer_list<int>, now int auto x2{1, 2}; // was std​::​initializer_list<int>, now ill-formed — end example]
Affected subclause: [dcl.fct]
Change: Make exception specifications be part of the type system.

Rationale: Improve type-safety.

Effect on original feature: Valid C++ 2014 code may fail to compile or change meaning in this revision of C++.
[Example 2: void g1() noexcept; void g2(); template<class T> int f(T *, T *); int x = f(g1, g2); // ill-formed; previously well-formed — end example]
Affected subclause: [dcl.init.aggr]
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.

Rationale: To increase convenience of aggregate initialization.

Effect on original feature: Valid C++ 2014 code may fail to compile or produce different results in this revision of C++; initialization from an empty initializer list will perform aggregate initialization instead of invoking a default constructor for the affected types.
[Example 3: struct derived; struct base { friend struct derived; private: base(); }; struct derived : base {}; derived d1{}; // error; the code was well-formed in C++ 2014 derived d2; // still OK — end example]

C.4.5 [class]: classes [diff.cpp14.class]

Affected subclause: [class.inhctor.init]
Change: Inheriting a constructor no longer injects a constructor into the derived class.

Rationale: Better interaction with other language features.

Effect on original feature: Valid C++ 2014 code that uses inheriting constructors may not be valid or may have different semantics.
A using-declaration that names a constructor now makes the corresponding base class constructors visible to initializations of the derived class rather than declaring additional derived class constructors.
[Example 1: struct A { template<typename T> A(T, typename T::type = 0); A(int); }; struct B : A { using A::A; B(int); }; B b(42L); // now calls B(int), used to call B<long>(long), // which called A(int) due to substitution failure // in A<long>(long). — end example]

C.4.6 [temp]: templates [diff.cpp14.temp]

Affected subclause: [temp.deduct.type]
Change: Allowance to deduce from the type of a non-type template argument.

Rationale: In combination with the ability to declare non-type template arguments with placeholder types, allows partial specializations to decompose from the type deduced for the non-type template argument.

Effect on original feature: Valid C++ 2014 code may fail to compile or produce different results in this revision of C++.
[Example 1: template <int N> struct A; template <typename T, T N> int foo(A<N> *) = delete; void foo(void *); void bar(A<0> *p) { foo(p); // ill-formed; previously well-formed } — end example]

C.4.7 [except]: exception handling [diff.cpp14.except]

Affected subclause: [except.spec]
Change: Remove dynamic exception specifications.

Rationale: Dynamic exception specifications were a deprecated feature that was complex and brittle in use.
They interacted badly with the type system, which became a more significant issue in this revision of C++ where (non-dynamic) exception specifications are part of the function type.

Effect on original feature: A valid C++ 2014 function declaration, member function declaration, function pointer declaration, or function reference declaration, if it has a potentially throwing dynamic exception specification, is rejected as ill-formed in this revision of C++.
Violating a non-throwing dynamic exception specification calls terminate rather than unexpected, and it is unspecified whether stack unwinding is performed prior to such a call.

C.4.8 [library]: library introduction [diff.cpp14.library]

Affected subclause: [headers]
Change: New headers.

Rationale: New functionality.

Effect on original feature: The following C++ headers are new: <any>, <charconv>, <execution>, <filesystem>, <memory_resource>, <optional>,
Valid C++ 2014 code that #includes headers with these names may be invalid in this revision of C++.
Affected subclause: [namespace.future]
Change: New reserved namespaces.

Rationale: Reserve namespaces for future revisions of the standard library that might otherwise be incompatible with existing programs.

Effect on original feature: The global namespaces std followed by an arbitrary sequence of digits ([lex.name]) are reserved for future standardization.
Valid C++ 2014 code that uses such a top-level namespace, e.g., std2, may be invalid in this revision of C++.

C.4.9 [utilities]: general utilities library [diff.cpp14.utilities]

Affected subclause: [func.wrap]
Change: Constructors taking allocators removed.

Rationale: No implementation consensus.

Effect on original feature: Valid C++ 2014 code may fail to compile or may change meaning in this revision of C++.
Specifically, constructing a std​::​function with an allocator is ill-formed and uses-allocator construction will not pass an allocator to std​::​function constructors in this revision of C++.
Affected subclause: [util.smartptr.shared]
Change: Different constraint on conversions from unique_ptr.

Rationale: Adding array support to shared_ptr, via the syntax shared_ptr<T[]> and shared_ptr<T[N]>.

Effect on original feature: Valid C++ 2014 code may fail to compile or may change meaning in this revision of C++.
[Example 1: #include <memory> std::unique_ptr<int[]> arr(new int[1]); std::shared_ptr<int> ptr(std::move(arr)); // error: int(*)[] is not compatible with int* — end example]

C.4.10 [strings]: strings library [diff.cpp14.string]

Affected subclause: [basic.string]
Change: Non-const .data() member added.

Rationale: The lack of a non-const .data() differed from the similar member of std​::​vector.
This change regularizes behavior.

Effect on original feature: Overloaded functions which have differing code paths for char* and const char* arguments will execute differently when called with a non-const string's .data() member in this revision of C++.
[Example 1: int f(char *) = delete; int f(const char *); string s; int x = f(s.data()); // ill-formed; previously well-formed — end example]

C.4.11 [containers]: containers library [diff.cpp14.containers]

Affected subclause: [associative.reqmts]
Change: Requirements change:
Rationale: Increase portability, clarification of associative container requirements.

Effect on original feature: Valid C++ 2014 code that attempts to use associative containers having a comparison object with non-const function call operator may fail to compile in this revision of C++.
[Example 1: #include <set> struct compare { bool operator()(int a, int b) { return a < b; } }; int main() { const std::set<int, compare> s; s.find(0); } — end example]

C.4.12 [depr]: compatibility features [diff.cpp14.depr]

Change: The class templates auto_ptr, unary_function, and binary_function, the function templates random_shuffle, and the function templates (and their return types) ptr_fun, mem_fun, mem_fun_ref, bind1st, and bind2nd are not defined.

Rationale: Superseded by new features.

Effect on original feature: Valid C++ 2014 code that uses these class templates and function templates may fail to compile in this revision of C++.
Change: Remove old iostreams members [depr.ios.members].

Rationale: Redundant feature for compatibility with pre-standard code has served its time.

Effect on original feature: A valid C++ 2014 program using these identifiers may be ill-formed in this revision of C++.

C.5 C++ and ISO C++ 2011 [diff.cpp11]

C.5.1 General [diff.cpp11.general]

Subclause [diff.cpp11] lists the differences between C++ and ISO C++ 2011, in addition to those listed above, by the chapters of this document.

C.5.2 [lex]: lexical conventions [diff.cpp11.lex]

Affected subclause: [lex.ppnumber]
Change: pp-number can contain one or more single quotes.

Rationale: Necessary to enable single quotes as digit separators.

Effect on original feature: Valid C++ 2011 code may fail to compile or may change meaning in this revision of C++.
For example, the following code is valid both in C++ 2011 and in this revision of C++, but the macro invocation produces different outcomes because the single quotes delimit a character-literal in C++ 2011, whereas they are digit separators in this revision of C++.
[Example 1: #define M(x, ...) __VA_ARGS__ int x[2] = { M(1'2,3'4, 5) }; // int x[2] = { 5 };      --- C++ 2011 // int x[2] = { 3'4, 5 }; --- this revision of C++ — end example]

C.5.3 [basic]: basics [diff.cpp11.basic]

Affected subclause: [basic.stc.dynamic.deallocation]
Change: New usual (non-placement) deallocator.

Rationale: Required for sized deallocation.

Effect on original feature: Valid C++ 2011 code can declare a global placement allocation function and deallocation function as follows: void* operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept;
In this revision of C++, however, the declaration of operator delete might match a predefined usual (non-placement) operator delete ([basic.stc.dynamic]).
If so, the program is ill-formed, as it was for class member allocation functions and deallocation functions ([expr.new]).

C.5.4 [expr]: expressions [diff.cpp11.expr]

Affected subclause: [expr.cond]
Change: A conditional expression with a throw expression as its second or third operand keeps the type and value category of the other operand.

Rationale: Formerly mandated conversions (lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions), especially the creation of the temporary due to lvalue-to-rvalue conversion, were considered gratuitous and surprising.

Effect on original feature: Valid C++ 2011 code that relies on the conversions may behave differently in this revision of C++.
[Example 1: struct S { int x = 1; void mf() { x = 2; } }; int f(bool cond) { S s; (cond ? s : throw 0).mf(); return s.x; }
In C++ 2011, f(true) returns 1.
In this revision of C++, it returns 2.
sizeof(true ? "" : throw 0)
In C++ 2011, the expression yields sizeof(const char*).
In this revision of C++, it yields sizeof(const char[1]).
— end example]

C.5.5 [dcl.dcl]: declarations [diff.cpp11.dcl.dcl]

Affected subclause: [dcl.constexpr]
Change: constexpr non-static member functions are not implicitly const member functions.

Rationale: Necessary to allow constexpr member functions to mutate the object.

Effect on original feature: Valid C++ 2011 code may fail to compile in this revision of C++.
[Example 1: struct S { constexpr const int &f(); int &f(); };
This code is valid in C++ 2011 but invalid in this revision of C++ because it declares the same member function twice with different return types.
— end example]
Affected subclause: [dcl.init.aggr]
Change: Classes with default member initializers can be aggregates.

Rationale: Necessary to allow default member initializers to be used by aggregate initialization.

Effect on original feature: Valid C++ 2011 code may fail to compile or may change meaning in this revision of C++.
[Example 2: struct S { // Aggregate in C++ 2014 onwards. int m = 1; }; struct X { operator int(); operator S(); }; X a{}; S b{a}; // uses copy constructor in C++ 2011, // performs aggregate initialization in this revision of C++ — end example]

C.5.6 [library]: library introduction [diff.cpp11.library]

Affected subclause: [headers]
Change: New header.

Rationale: New functionality.

Effect on original feature: The C++ header <shared_mutex> is new.
Valid C++ 2011 code that #includes a header with that name may be invalid in this revision of C++.

C.5.7 [input.output]: input/output library [diff.cpp11.input.output]

Affected subclause: [c.files]
Change: gets is not defined.

Rationale: Use of gets is considered dangerous.

Effect on original feature: Valid C++ 2011 code that uses the gets function may fail to compile in this revision of C++.

C.6 C++ and ISO C++ 2003 [diff.cpp03]

C.6.1 General [diff.cpp03.general]

Subclause [diff.cpp03] lists the differences between C++ and ISO C++ 2003, in addition to those listed above, by the chapters of this document.

C.6.2 [lex]: lexical conventions [diff.cpp03.lex]

Affected subclause: [lex.pptoken]
Change: New kinds of string-literals.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this revision of C++.
Specifically, macros named R, u8, u8R, u, uR, U, UR, or LR will not be expanded when adjacent to a string-literal but will be interpreted as part of the string-literal.
[Example 1: #define u8 "abc" const char* s = u8"def"; // Previously "abcdef", now "def" — end example]
Affected subclause: [lex.pptoken]
Change: User-defined literal string support.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this revision of C++.
[Example 2: #define _x "there" "hello"_x // #1
Previously, #1 would have consisted of two separate preprocessing tokens and the macro _x would have been expanded.
In this revision of C++, #1 consists of a single preprocessing token, so the macro is not expanded.
— end example]
Affected subclause: [lex.key]
Change: New keywords.

Rationale: Required for new features.

Effect on original feature: Added to Table 5, the following identifiers are new keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local.
Valid C++ 2003 code using these identifiers is invalid in this revision of C++.
Affected subclause: [lex.icon]
Change: Type of integer literals.

Rationale: C99 compatibility.

Effect on original feature: Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.

C.6.3 [expr]: expressions [diff.cpp03.expr]

Affected subclause: [conv.ptr]
Change: Only literals are integer null pointer constants.

Rationale: Removing surprising interactions with templates and constant expressions.

Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this revision of C++.
[Example 1: void f(void *); // #1 void f(...); // #2 template<int N> void g() { f(0*N); // calls #2; used to call #1 } — end example]
Affected subclause: [expr.typeid]
Change: Evaluation of operands in typeid.

Rationale: Introduce additional expression value categories.

Effect on original feature: Valid C++ 2003 code that uses xvalues as operands for typeid may change behavior in this revision of C++.
[Example 2: void f() { struct B { B() {} virtual ~B() { } }; struct C { B b; }; typeid(C().b); // unevaluated in C++ 2003, evaluated in C++ 2011 } — end example]
Affected subclause: [expr.mul]
Change: Specify rounding for results of integer / and %.

Rationale: Increase portability, C99 compatibility.

Effect on original feature: Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas this revision of C++ always rounds the result toward 0.
Affected subclause: [expr.log.and]
Change: && is valid in a type-name.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this revision of C++.
[Example 3: bool b1 = new int && false; // previously false, now ill-formed struct S { operator int(); }; bool b2 = &S::operator int && false; // previously false, now ill-formed — end example]
Affected subclause: [expr.cond]
Change: Fewer copies in the conditional operator.

Rationale: Introduce additional expression value categories.

Effect on original feature: Valid C++ 2003 code that uses xvalues as operands for the conditional operator may change behavior in this revision of C++.
[Example 4: void f() { struct B { B() {} B(const B&) { } }; struct D : B {}; struct BB { B b; }; struct DD { D d; }; true ? BB().b : DD().d; // additional copy in C++ 2003, no copy or move in C++ 2011 } — end example]

C.6.4 [dcl.dcl]: declarations [diff.cpp03.dcl.dcl]

Affected subclause: [dcl.spec]
Change: Remove auto as a storage class specifier.

Rationale: New feature.

Effect on original feature: Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in this revision of C++.
In this revision of C++, auto indicates that the type of a variable is to be deduced from its initializer expression.
Affected subclause: [dcl.init.list]
Change: Narrowing restrictions in aggregate initializers.

Rationale: Catches bugs.

Effect on original feature: Valid C++ 2003 code may fail to compile in this revision of C++.
[Example 1: int x[] = { 2.0 };
This code is valid in C++ 2003 but invalid in this revision of C++ because double to int is a narrowing conversion.
— end example]
Affected subclause: [dcl.link]
Change: Names declared in an anonymous namespace changed from external linkage to internal linkage; language linkage applies to names with external linkage only.

Rationale: Alignment with user expectations.

Effect on original feature: Valid C++ 2003 code may violate the one-definition rule ([basic.def.odr]) in this revision of C++.
[Example 2: namespace { extern "C" { extern int x; } } // #1, previously external linkage and C language linkage, // now internal linkage and C++ language linkage namespace A { extern "C" int x = 42; } // #2, external linkage and C language linkage int main(void) { return x; }
This code is valid in C++ 2003, but #2 is not a definition for #1 in this revision of C++, violating the one-definition rule.
— end example]

C.6.5 [class]: classes [diff.cpp03.class]

Affected subclauses: [class.default.ctor], [class.dtor], [class.copy.ctor], and [class.copy.assign]
Change: Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.

Rationale: Improves template argument deduction failure.

Effect on original feature: A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expression that is not potentially evaluated) becomes ill-formed.
Affected subclause: [class.dtor]
Change: User-declared destructors have an implicit exception specification.

Rationale: Clarification of destructor requirements.

Effect on original feature: Valid C++ 2003 code may execute differently in this revision of C++.
In particular, destructors that throw exceptions will call std​::​terminate (without calling std​::​unexpected) if their exception specification is non-throwing.

C.6.6 [temp]: templates [diff.cpp03.temp]

Affected subclause: [temp.param]
Change: Repurpose export for modules ([module], [cpp.module], [cpp.import]).

Rationale: No implementation consensus for the C++ 2003 meaning of export.

Effect on original feature: A valid C++ 2003 program containing export is ill-formed in this revision of C++.
Affected subclause: [temp.arg]
Change: Remove whitespace requirement for nested closing template right angle brackets.

Rationale: Considered a persistent but minor annoyance.
Template aliases representing non-class types would exacerbate whitespace issues.

Effect on original feature: Change to semantics of well-defined expression.
A valid C++ 2003 expression containing a right angle bracket (“>”) followed immediately by another right angle bracket may now be treated as closing two templates.
[Example 1: template <class T> struct X { }; template <int N> struct Y { }; X< Y< 1 >> 2 > > x;
This code is valid in C++ 2003 because “>>” is a right-shift operator, but invalid in this revision of C++ because “>>” closes two templates.
— end example]
Affected subclause: [temp.dep.candidate]
Change: Allow dependent calls of functions with internal linkage.

Rationale: Overly constrained, simplify overload resolution rules.

Effect on original feature: A valid C++ 2003 program can get a different result in this revision of C++.

C.6.7 [library]: library introduction [diff.cpp03.library]

Affected: [library][exec]
Change: New reserved identifiers.

Rationale: Required by new features.

Effect on original feature: Valid C++ 2003 code that uses any identifiers added to the C++ standard library by later revisions of C++ may fail to compile or produce different results in this revision of C++.
A comprehensive list of identifiers used by the C++ standard library can be found in the Index of Library Names in this document.
Affected subclause: [headers]
Change: New headers.

Rationale: New functionality.

In addition the following C compatibility headers are new: <cfenv>, <cinttypes>, <cstdint>, and <cuchar>.
Valid C++ 2003 code that #includes headers with these names may be invalid in this revision of C++.
Affected subclause: [swappable.requirements]
Change: Function swap moved to a different header.

Rationale: Remove dependency on <algorithm> for swap.

Effect on original feature: Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>.
Affected subclause: [namespace.posix]
Change: New reserved namespace.

Rationale: New functionality.

Effect on original feature: The global namespace posix is now reserved for standardization.
Valid C++ 2003 code that uses a top-level namespace posix may be invalid in this revision of C++.
Affected subclause: [res.on.macro.definitions]
Change: Additional restrictions on macro names.

Rationale: Avoid hard to diagnose or non-portable constructs.

Effect on original feature: Names of attribute identifiers may not be used as macro names.
Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in this revision of C++.

C.6.8 [support]: language support library [diff.cpp03.language.support]

Affected subclause: [new.delete.single]
Change: operator new may throw exceptions other than std​::​bad_alloc.

Rationale: Consistent application of noexcept.

Effect on original feature: Valid C++ 2003 code that assumes that global operator new only throws std​::​bad_alloc may execute differently in this revision of C++.
Valid C++ 2003 code that replaces the global replaceable operator new is ill-formed in this revision of C++, because the exception specification of throw(std​::​bad_alloc) was removed.

C.6.9 [diagnostics]: diagnostics library [diff.cpp03.diagnostics]

Affected subclause: [errno]
Change: Thread-local error numbers.

Rationale: Support for new thread facilities.

Effect on original feature: Valid but implementation-specific C++ 2003 code that relies on errno being the same across threads may change behavior in this revision of C++.

C.6.10 [utilities]: general utilities library [diff.cpp03.utilities]

Affected subclauses: [refwrap], [arithmetic.operations], [comparisons], [logical.operations], and [bitwise.operations]
Change: Standard function object types no longer derived from std​::​unary_function or std​::​binary_function.

Rationale: Superseded by new feature; unary_function and binary_function are no longer defined.

Effect on original feature: Valid C++ 2003 code that depends on function object types being derived from unary_function or binary_function may fail to compile in this revision of C++.

C.6.11 [strings]: strings library [diff.cpp03.strings]

Affected subclause: [string.classes]
Change: basic_string requirements no longer allow reference-counted strings.

Rationale: Invalidation is subtly different with reference-counted strings.
This change regularizes behavior.

Effect on original feature: Valid C++ 2003 code may execute differently in this revision of C++.
Affected subclause: [string.require]
Change: Loosen basic_string invalidation rules.

Rationale: Allow small-string optimization.

Effect on original feature: Valid C++ 2003 code may execute differently in this revision of C++.
Some const member functions, such as data and c_str, no longer invalidate iterators.

C.6.12 [containers]: containers library [diff.cpp03.containers]

Affected subclause: [container.requirements]
Change: Complexity of size() member functions now constant.

Rationale: Lack of specification of complexity of size() resulted in divergent implementations with inconsistent performance characteristics.

Effect on original feature: Some container implementations that conform to C++ 2003 may not conform to the specified size() requirements in this revision of C++.
Adjusting containers such as std​::​list to the stricter requirements may require incompatible changes.
Affected subclause: [container.requirements]
Change: Requirements change: relaxation.

Rationale: Clarification.

Effect on original feature: Valid C++ 2003 code that attempts to meet the specified container requirements may now be over-specified.
Code that attempted to be portable across containers may need to be adjusted as follows:
  • not all containers provide size(); use empty() instead of size() == 0;
  • not all containers are empty after construction (array);
  • not all containers have constant complexity for swap() (array).
Affected subclause: [container.requirements]
Change: Requirements change: default constructible.

Rationale: Clarification of container requirements.

Effect on original feature: Valid C++ 2003 code that attempts to explicitly instantiate a container using a user-defined type with no default constructor may fail to compile.
Affected subclauses: [sequence.reqmts] and [associative.reqmts]
Change: Signature changes: from void return types.

Rationale: Old signature threw away useful information that may be expensive to recalculate.

Effect on original feature: The following member functions have changed:
  • erase(iter) for set, multiset, map, multimap
  • erase(begin, end) for set, multiset, map, multimap
  • insert(pos, num, val) for vector, deque, list, forward_list
  • insert(pos, beg, end) for vector, deque, list, forward_list
Valid C++ 2003 code that relies on these functions returning void (e.g., code that creates a pointer to member function that points to one of these functions) will fail to compile with this revision of C++.
Affected subclauses: [sequence.reqmts] and [associative.reqmts]
Change: Signature changes: from iterator to const_iterator parameters.

Rationale: Overspecification.

Effect on original feature: The signatures of the following member functions changed from taking an iterator to taking a const_iterator:
  • insert(iter, val) for vector, deque, list, set, multiset, map, multimap
  • insert(pos, beg, end) for vector, deque, list, forward_list
  • erase(begin, end) for set, multiset, map, multimap
  • all forms of list​::​splice
  • all forms of list​::​merge
Valid C++ 2003 code that uses these functions may fail to compile with this revision of C++.
Affected subclauses: [sequence.reqmts] and [associative.reqmts]
Change: Signature changes: resize.

Rationale: Performance, compatibility with move semantics.

Effect on original feature: For vector, deque, and list the fill value passed to resize is now passed by reference instead of by value, and an additional overload of resize has been added.
Valid C++ 2003 code that uses this function may fail to compile with this revision of C++.

C.6.13 [algorithms]: algorithms library [diff.cpp03.algorithms]

Affected subclause: [algorithms.general]
Change: Result state of inputs after application of some algorithms.

Rationale: Required by new feature.

Effect on original feature: A valid C++ 2003 program may detect that an object with a valid but unspecified state has a different valid but unspecified state with this revision of C++.
For example, std​::​remove and std​::​remove_if may leave the tail of the input sequence with a different set of values than previously.

C.6.14 [numerics]: numerics library [diff.cpp03.numerics]

Affected subclause: [complex.numbers]
Change: Specified representation of complex numbers.

Rationale: Compatibility with C99.

Effect on original feature: Valid C++ 2003 code that uses implementation-specific knowledge about the binary representation of the required template specializations of std​::​complex may not be compatible with this revision of C++.

C.6.15 [localization]: localization library [diff.cpp03.locale]

Affected subclause: [facet.num.get.virtuals]
Change: The num_get facet recognizes hexadecimal floating point values.

Rationale: Required by new feature.

Effect on original feature: Valid C++ 2003 code may have different behavior in this revision of C++.

C.6.16 [input.output]: input/output library [diff.cpp03.input.output]

Affected subclauses: [istream.sentry], [ostream.sentry], and [iostate.flags]
Change: Specify use of explicit in existing boolean conversion functions.

Rationale: Clarify intentions, avoid workarounds.

Effect on original feature: Valid C++ 2003 code that relies on implicit boolean conversions will fail to compile with this revision of C++.
Such conversions occur in the following conditions:
  • passing a value to a function that takes an argument of type bool;
  • using operator== to compare to false or true;
  • returning a value from a function with a return type of bool;
  • initializing members of type bool via aggregate initialization;
  • initializing a const bool& which would bind to a temporary object.
Affected subclause: [ios.failure]
Change: Change base class of std​::​ios_base​::​failure.

Rationale: More detailed error messages.

Effect on original feature: std​::​ios_base​::​failure is no longer derived directly from std​::​exception, but is now derived from std​::​system_error, which in turn is derived from std​::​runtime_error.
Valid C++ 2003 code that assumes that std​::​ios_base​::​failure is derived directly from std​::​exception may execute differently in this revision of C++.
Affected subclause: [ios.base]
Change: Flag types in std​::​ios_base are now bitmasks with values defined as constexpr static members.

Rationale: Required for new features.

Effect on original feature: Valid C++ 2003 code that relies on std​::​ios_base flag types being represented as std​::​bitset or as an integer type may fail to compile with this revision of C++.
[Example 1: #include <iostream> int main() { int flag = std::ios_base::hex; std::cout.setf(flag); // error: setf does not take argument of type int } — end example]

C.7 C++ and C [diff.iso]

C.7.1 General [diff.iso.general]

Subclause [diff.iso] lists the differences between C++ and C, in addition to those listed above, by the chapters of this document.

C.7.2 [lex]: lexical conventions [diff.lex]

Affected subclause: [lex.key]
Change: New Keywords
New keywords are added to C++; see [lex.key].

Rationale: These keywords were added in order to implement the new semantics of C++.

Effect on original feature: Change to semantics of well-defined feature.
Any C programs that used any of these keywords as identifiers are not valid C++ programs.

Difficulty of converting: Syntactic transformation.
Converting one specific program is easy.
Converting a large collection of related programs takes more work.

How widely used: Common.
Affected subclause: [lex.ccon]
Change: Type of character-literal is changed from int to char.

Rationale: This is needed for improved overloaded function argument type matching.
[Example 1: int function( int i ); int function( char c ); function( 'x' );
It is preferable that this call match the second version of function rather than the first.
— end example]

Effect on original feature: Change to semantics of well-defined feature.
C programs which depend on sizeof('x') == sizeof(int) will not work the same as C++ programs.

Difficulty of converting: Simple.

How widely used: Programs which depend upon sizeof('x') are probably rare.
Affected subclause: [lex.string]
Change: Concatenated string-literals can no longer have conflicting encoding-prefixes.

Rationale: Removal of non-portable feature.

Effect on original feature: Concatenation of string-literals with different encoding-prefixes is now ill-formed.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.
Affected subclause: [lex.string]
Change: String literals made const.

The type of a string-literal is changed from “array of char” to “array of const char.
The type of a UTF-8 string literal is changed from “array of char” to “array of const char8_t.
The type of a UTF-16 string literal is changed from “array of some-integer-type” to “array of const char16_t.
The type of a UTF-32 string literal is changed from “array of some-integer-type” to “array of const char32_t.
The type of a wide string literal is changed from “array of wchar_t” to “array of const wchar_t.

Rationale: This avoids calling an inappropriate overloaded function, which might expect to be able to modify its argument.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Syntactic transformation.
The fix is to add a cast: char* p = "abc"; // valid in C, invalid in C++ void f(char*) { char* p = (char*)"abc"; // OK, cast added f(p); f((char*)"def"); // OK, cast added }
How widely used: Programs that have a legitimate reason to treat string literal objects as potentially modifiable memory are probably rare.

C.7.3 [basic]: basics [diff.basic]

Affected subclause: [basic.def]
Change: C++ does not have “tentative definitions” as in C.
[Example 1: 
At file scope, int i; int i; is valid in C, invalid in C++.
— end example]
This makes it impossible to define mutually referential file-local objects with static storage duration, if initializers are restricted to the syntactic forms of C.
[Example 2: struct X { int i; struct X* next; }; static struct X a; static struct X b = { 0, &a }; static struct X a = { 1, &b }; — end example]

Rationale: This avoids having different initialization rules for fundamental types and user-defined types.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
In C++, the initializer for one of a set of mutually-referential file-local objects with static storage duration must invoke a function call to achieve the initialization.

How widely used: Seldom.
Affected subclause: [basic.scope]
Change: A struct is a scope in C++, not in C.
[Example 3: 
struct X { struct Y { int a; } b; }; struct Y c; is valid in C but not in C++, which would require X​::​Y c;.
— end example]

Rationale: Class scope is crucial to C++, and a struct is a class.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: C programs use struct extremely frequently, but the change is only noticeable when struct, enumeration, or enumerator names are referred to outside the struct.
The latter is probably rare.
Affected subclause: [basic.link] [also [dcl.type]]
Change: A name of file scope that is explicitly declared const, and not explicitly declared extern, has internal linkage, while in C it would have external linkage.

Rationale: Because const objects may be used as values during translation in C++, this feature urges programmers to provide an explicit initializer for each const object.
This feature allows the user to put const objects in source files that are included in more than one translation unit.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Seldom.
Affected subclause: [basic.start.main]
Change: The main function cannot be called recursively and cannot have its address taken.

Rationale: The main function may require special actions.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Trivial: create an intermediary function such as mymain(argc, argv).

How widely used: Seldom.
Affected subclause: [basic.types]
Change: C allows “compatible types” in several places, C++ does not.

For example, otherwise-identical struct types with different tag names are “compatible” in C but are distinctly different types in C++.

Rationale: Stricter type checking is essential for C++.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
The “typesafe linkage” mechanism will find many, but not all, of such problems.
Those problems not found by typesafe linkage will continue to function properly, according to the “layout compatibility rules” of this document.

How widely used: Common.

C.7.4 [expr]: expressions [diff.expr]

Affected subclause: [conv.ptr]
Change: Converting void* to a pointer-to-object type requires casting.
[Example 1: char a[10]; void* b=a; void foo() { char* c=b; }
C accepts this usage of pointer to void being assigned to a pointer to object type.
C++ does not.
— end example]

Rationale: C++ tries harder than C to enforce compile-time type safety.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Can be automated.
Violations will be diagnosed by the C++ translator.
The fix is to add a cast.
[Example 2: char* c = (char*) b; — end example]

How widely used: This is fairly widely used but it is good programming practice to add the cast when assigning pointer-to-void to pointer-to-object.
Some C translators will give a warning if the cast is not used.
Affected subclause: [expr.arith.conv]
Change: Operations mixing a value of an enumeration type and a value of a different enumeration type or of a floating-point type are not valid.
[Example 3: enum E1 { e }; enum E2 { f }; int b = e <= 3.7; // valid in C; ill-formed in C++ int k = f - e; // valid in C; ill-formed in C++ int x = 1 ? e : f; // valid in C; ill-formed in C++ — end example]

Rationale: Reinforcing type safety in C++.

Effect on original feature: Well-formed C code will not compile with this International Standard.

Difficulty of converting: Violations will be diagnosed by the C++ translator.
The original behavior can be restored with a cast or integral promotion.
[Example 4: enum E1 { e }; enum E2 { f }; int b = (int)e <= 3.7; int k = +f - e; — end example]

How widely used: Uncommon.
Affected subclauses: [expr.post.incr] and [expr.pre.incr]
Change: Decrement operator is not allowed with bool operand.

Rationale: Feature with surprising semantics.

Effect on original feature: A valid C expression utilizing the decrement operator on a bool lvalue (for instance, via the C typedef in <stdbool.h>) is ill-formed in C++.
Affected subclauses: [expr.sizeof] and [expr.cast]
Change: In C++, types can only be defined in declarations, not in expressions.

In C, a sizeof expression or cast expression may define a new type.
[Example 5: 
p = (void*)(struct x {int i;} *)0; defines a new type, struct x.
— end example]

Rationale: This prohibition helps to clarify the location of definitions in the source code.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.
Affected subclauses: [expr.rel] and [expr.eq]
Change: C allows directly comparing two objects of array type; C++ does not.

Rationale: The behavior is confusing because it compares not the contents of the two arrays, but their addresses.

Effect on original feature: Deletion of semantically well-defined feature that had unspecified behavior in common use cases.

Difficulty of converting: Violations will be diagnosed by the C++ translator.
The original behavior can be replicated by explicitly casting either array to a pointer, such as by using a unary +.
[Example 6: int arr1[5]; int arr2[5]; int same = arr1 == arr2; // valid C, ill-formed C++ int idem = arr1 == +arr2; // valid in both C and C++ — end example]

How widely used: Rare.
Affected subclauses: [expr.cond], [expr.ass], and [expr.comma]
Change: The result of a conditional expression, an assignment expression, or a comma expression may be an lvalue.

Rationale: C++ is an object-oriented language, placing relatively more emphasis on lvalues.
For example, function calls may yield lvalues.

Effect on original feature: Change to semantics of well-defined feature.
Some C expressions that implicitly rely on lvalue-to-rvalue conversions will yield different results.
[Example 7: 
char arr[100]; sizeof(0, arr) yields 100 in C++ and sizeof(char*) in C.
— end example]

Difficulty of converting: Programs must add explicit casts to the appropriate rvalue.

How widely used: Rare.

C.7.5 [stmt.stmt]: statements [diff.stat]

Affected subclauses: [stmt.switch] and [stmt.goto]
Change: It is now invalid to jump past a declaration with explicit or implicit initializer (except across entire block not entered).

Rationale: Constructors used in initializers may allocate resources which need to be de-allocated upon leaving the block.
Allowing jump past initializers would require complicated runtime determination of allocation.
Furthermore, many operations on such an uninitialized object have undefined behavior.
With this simple compile-time rule, C++ assures that if an initialized variable is in scope, then it has assuredly been initialized.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Seldom.
Affected subclause: [stmt.return]
Change: It is now invalid to return (explicitly or implicitly) from a function which is declared to return a value without actually returning a value.

Rationale: The caller and callee may assume fairly elaborate return-value mechanisms for the return of class objects.
If some flow paths execute a return without specifying any value, the implementation must embody many more complications.
Besides, promising to return a value of a given type, and then not returning such a value, has always been recognized to be a questionable practice, tolerated only because very-old C had no distinction between functions with void and int return types.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
Add an appropriate return value to the source code, such as zero.

How widely used: Seldom.
For several years, many existing C implementations have produced warnings in this case.

C.7.6 [dcl.dcl]: declarations [diff.dcl]

Affected subclause: [dcl.stc]
Change: In C++, the static or extern specifiers can only be applied to names of objects or functions.

Using these specifiers with type declarations is illegal in C++.
In C, these specifiers are ignored when used on type declarations.
[Example 1: static struct S { // valid C, invalid in C++ int i; }; — end example]

Rationale: Storage class specifiers don't have any meaning when associated with a type.
In C++, class members can be declared with the static storage class specifier.
Storage class specifiers on type declarations can be confusing for users.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.
Affected subclause: [dcl.stc]
Change: In C++, register is not a storage class specifier.

Rationale: The storage class specifier had no effect in C++.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Common.
Affected subclause: [dcl.typedef]
Change: A C++ typedef-name must be different from any class type name declared in the same scope (except if the typedef is a synonym of the class name with the same name).
In C, a typedef-name and a struct tag name declared in the same scope can have the same name (because they have different name spaces).
[Example 2: typedef struct name1 { /* ... */ } name1; // valid C and C++ struct name { /* ... */ }; typedef int name; // valid C, invalid C++ — end example]

Rationale: For ease of use, C++ doesn't require that a type name be prefixed with the keywords class, struct or union when used in object declarations or type casts.
[Example 3: class name { /* ... */ }; name i; // i has type class name — end example]

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
One of the 2 types has to be renamed.

How widely used: Seldom.
Affected subclause: [dcl.type] [see also [basic.link]]
Change: Const objects must be initialized in C++ but can be left uninitialized in C.
Rationale: A const object cannot be assigned to so it must be initialized to hold a useful value.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Seldom.
Affected subclause: [dcl.spec.auto]
Change: The keyword auto cannot be used as a storage class specifier.
[Example 4: void f() { auto int x; // valid C, invalid C++ } — end example]

Rationale: Allowing the use of auto to deduce the type of a variable from its initializer results in undesired interpretations of auto as a storage class specifier in certain contexts.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Rare.
Affected subclause: [dcl.fct]
Change: In C++, a function declared with an empty parameter list takes no arguments.
In C, an empty parameter list means that the number and type of the function arguments are unknown.
[Example 5: int f(); // means int f(void) in C++ // int f( unknown ) in C — end example]

Rationale: This is to avoid function calls with the wrong number or type of arguments.

Effect on original feature: Change to semantics of well-defined feature.
This feature was marked as “obsolescent” in C.
Difficulty of converting: Syntactic transformation.
The function declarations using C incomplete declaration style must be completed to become full prototype declarations.
A program may need to be updated further if different calls to the same (non-prototype) function have different numbers of arguments or if the type of corresponding arguments differed.

How widely used: Common.
Affected subclause: [dcl.fct] [see [expr.sizeof]]
Change: In C++, types may not be defined in return or parameter types.
In C, these type definitions are allowed.
[Example 6: void f( struct S { int a; } arg ) {} // valid C, invalid C++ enum E { A, B, C } f() {} // valid C, invalid C++ — end example]

Rationale: When comparing types in different translation units, C++ relies on name equivalence when C relies on structural equivalence.
Regarding parameter types: since the type defined in a parameter list would be in the scope of the function, the only legal calls in C++ would be from within the function itself.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
The type definitions must be moved to file scope, or in header files.

How widely used: Seldom.
This style of type definition is seen as poor coding style.
Affected subclause: [dcl.fct.def]
Change: In C++, the syntax for function definition excludes the “old-style” C function.
In C, “old-style” syntax is allowed, but deprecated as “obsolescent”.

Rationale: Prototypes are essential to type safety.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Common in old programs, but already known to be obsolescent.
Affected subclause: [dcl.init.aggr]
Change: In C++, designated initialization support is restricted compared to the corresponding functionality in C.
In C++, designators for non-static data members must be specified in declaration order, designators for array elements and nested designators are not supported, and designated and non-designated initializers cannot be mixed in the same initializer list.
[Example 7: struct A { int x, y; }; struct B { struct A a; }; struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ int arr[3] = {[1] = 5}; // valid C, invalid C++ struct B b = {.a.x = 0}; // valid C, invalid C++ struct A c = {.x = 1, 2}; // valid C, invalid C++ — end example]

Rationale: In C++, members are destroyed in reverse construction order and the elements of an initializer list are evaluated in lexical order, so member initializers must be specified in order.
Array designators conflict with lambda-expression syntax.
Nested designators are seldom used.

Effect on original feature: Deletion of feature that is incompatible with C++.

Difficulty of converting: Syntactic transformation.

How widely used: Out-of-order initializers are common.
The other features are seldom used.
Affected subclause: [dcl.init.string]
Change: In C++, when initializing an array of character with a string, the number of characters in the string (including the terminating '\0') must not exceed the number of elements in the array.
In C, an array can be initialized with a string even if the array is not large enough to contain the string-terminating '\0'.
[Example 8: char array[4] = "abcd"; // valid C, invalid C++ — end example]

Rationale: When these non-terminated arrays are manipulated by standard string functions, there is potential for major catastrophe.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
The arrays must be declared one element bigger to contain the string terminating '\0'.

How widely used: Seldom.
This style of array initialization is seen as poor coding style.
Affected subclause: [dcl.enum]
Change: C++ objects of enumeration type can only be assigned values of the same enumeration type.
In C, objects of enumeration type can be assigned values of any integral type.
[Example 9: enum color { red, blue, green }; enum color c = 1; // valid C, invalid C++ — end example]

Rationale: The type-safe nature of C++.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.
(The type error produced by the assignment can be automatically corrected by applying an explicit cast.)

How widely used: Common.
Affected subclause: [dcl.enum]
Change: In C++, the type of an enumerator is its enumeration.
In C, the type of an enumerator is int.
[Example 10: enum e { A }; sizeof(A) == sizeof(int) // in C sizeof(A) == sizeof(e) // in C++ /* and sizeof(int) is not necessarily equal to sizeof(e) */ — end example]

Rationale: In C++, an enumeration is a distinct type.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Seldom.
The only time this affects existing C code is when the size of an enumerator is taken.
Taking the size of an enumerator is not a common C coding practice.
Affected subclause: [dcl.align]
Change: In C++, an alignment-specifier is an attribute-specifier.
In C, an alignment-specifier is a declaration-specifier.
[Example 11: #include <stdalign.h> unsigned alignas(8) int x; // valid C, invalid C++ unsigned int y alignas(8); // valid C++, invalid C — end example]

Rationale: C++ requires unambiguous placement of the alignment-specifier.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.

C.7.7 [class]: classes [diff.class]

Affected subclause: [class.name] [see also [dcl.typedef]]
Change: In C++, a class declaration introduces the class name into the scope where it is declared and hides any object, function or other declaration of that name in an enclosing scope.
In C, an inner scope declaration of a struct tag name never hides the name of an object or function in an outer scope.
[Example 1: int x[99]; void f() { struct x { int a; }; sizeof(x); /* size of the array in C */ /* size of the struct in C++ */ } — end example]

Rationale: This is one of the few incompatibilities between C and C++ that can be attributed to the new C++ name space definition where a name can be declared as a type and as a non-type in a single scope causing the non-type name to hide the type name and requiring that the keywords class, struct, union or enum be used to refer to the type name.
This new name space definition provides important notational conveniences to C++ programmers and helps making the use of the user-defined types as similar as possible to the use of fundamental types.
The advantages of the new name space definition were judged to outweigh by far the incompatibility with C described above.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.
If the hidden name that needs to be accessed is at global scope, the ​::​ C++ operator can be used.
If the hidden name is at block scope, either the type or the struct tag has to be renamed.

How widely used: Seldom.
Affected subclause: [class.copy.ctor]
Change: Copying volatile objects.
The implicitly-declared copy constructor and implicitly-declared copy assignment operator cannot make a copy of a volatile lvalue.
[Example 2: 
The following is valid in C: struct X { int i; }; volatile struct X x1 = {0}; struct X x2 = x1; // invalid C++ struct X x3; x3 = x1; // also invalid C++
— end example]

Rationale: Several alternatives were debated at length.
Changing the parameter to volatile const X& would greatly complicate the generation of efficient code for class objects.
Discussion of providing two alternative signatures for these implicitly-defined operations raised unanswered concerns about creating ambiguities and complicating the rules that specify the formation of these operators according to the bases and members.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
If volatile semantics are required for the copy, a user-declared constructor or assignment must be provided.
If non-volatile semantics are required, an explicit const_cast can be used.

How widely used: Seldom.
Affected subclause: [class.bit]
Change: Bit-fields of type plain int are signed.

Rationale: The signedness needs to be consistent among template specializations.
For consistency, the implementation freedom was eliminated for non-dependent types, too.

Effect on original feature: The choice is implementation-defined in C, but not so in C++.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.
Affected subclause: [class.nest]
Change: In C++, the name of a nested class is local to its enclosing class.
In C the name of the nested class belongs to the same scope as the name of the outermost enclosing class.
[Example 3: struct X { struct Y { /* ... */ } y; }; struct Y yy; // valid C, invalid C++ — end example]

Rationale: C++ classes have member functions which require that classes establish scopes.
The C rule would leave classes as an incomplete scope mechanism which would prevent C++ programmers from maintaining locality within a class.
A coherent set of scope rules for C++ based on the C rule would be very complicated and C++ programmers would be unable to predict reliably the meanings of nontrivial examples involving nested or local functions.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.
To make the struct type name visible in the scope of the enclosing struct, the struct tag can be declared in the scope of the enclosing struct, before the enclosing struct is defined.
[Example 4: struct Y; // struct Y and struct X are at the same scope struct X { struct Y { /* ... */ } y; }; — end example]
All the definitions of C struct types enclosed in other struct definitions and accessed outside the scope of the enclosing struct can be exported to the scope of the enclosing struct.
Note: this is a consequence of the difference in scope rules, which is documented in [basic.scope].

How widely used: Seldom.
Affected subclause: [class.member.lookup]
Change: In C++, a typedef-name may not be redeclared in a class definition after being used in that definition.
[Example 5: typedef int I; struct S { I i; int I; // valid C, invalid C++ }; — end example]

Rationale: When classes become complicated, allowing such a redefinition after the type has been used can create confusion for C++ programmers as to what the meaning of I really is.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
Either the type or the struct member has to be renamed.

How widely used: Seldom.

C.7.8 [cpp]: preprocessing directives [diff.cpp]

Affected subclause: [cpp.predefined]
Change: Whether __STDC__ is defined and if so, what its value is, are implementation-defined.

Rationale: C++ is not identical to C.
Mandating that __STDC__ be defined would require that translators make an incorrect claim.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.

How widely used: Programs and headers that reference __STDC__ are quite common.

C.8 C standard library [diff.library]

C.8.1 General [diff.library.general]

Subclause [diff.library] summarizes the explicit changes in headers, definitions, declarations, or behavior between the C standard library in the C standard and the parts of the C++ standard library that were included from the C standard library.

C.8.2 Modifications to headers [diff.mods.to.headers]

For compatibility with the C standard library, the C++ standard library provides the C headers enumerated in [support.c.headers].
There are no C++ headers for the C standard library's headers <stdnoreturn.h> and <threads.h>, nor are these headers from the C standard library headers themselves part of C++.
The C headers <complex.h> and <tgmath.h> do not contain any of the content from the C standard library and instead merely include other headers from the C++ standard library.

C.8.3 Modifications to definitions [diff.mods.to.definitions]

C.8.3.1 Types char16_t and char32_t [diff.char16]

The types char16_t and char32_t are distinct types rather than typedefs to existing integral types.
The tokens char16_t and char32_t are keywords in C++ ([lex.key]).
They do not appear as macro or type names defined in <cuchar>.

C.8.3.2 Type wchar_t [diff.wchar.t]

The type wchar_t is a distinct type rather than a typedef to an existing integral type.
The token wchar_t is a keyword in C++ ([lex.key]).
It does not appear as a macro or type name defined in any of <cstddef>, <cstdlib>, or <cwchar>.

C.8.3.3 Header <assert.h> [diff.header.assert.h]

The token static_assert is a keyword in C++.
It does not appear as a macro name defined in <cassert>.

C.8.3.4 Header <iso646.h> [diff.header.iso646.h]

The tokens and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, and xor_eq are keywords in C++ ([lex.key]), and are not introduced as macros by <iso646.h>.

C.8.3.5 Header <stdalign.h> [diff.header.stdalign.h]

The token alignas is a keyword in C++ ([lex.key]), and is not introduced as a macro by <stdalign.h>.

C.8.3.6 Header <stdbool.h> [diff.header.stdbool.h]

The tokens bool, true, and false are keywords in C++ ([lex.key]), and are not introduced as macros by <stdbool.h>.

C.8.3.7 Macro NULL [diff.null]

The macro NULL, defined in any of <clocale>, <cstddef>, <cstdio>, <cstdlib>, <cstring>, <ctime>, or <cwchar>, is an implementation-defined null pointer constant in C++ ([support.types]).

C.8.4 Modifications to declarations [diff.mods.to.declarations]

Header <cstring>: The following functions have different declarations:
Subclause [cstring.syn] describes the changes.
Header <cwchar>: The following functions have different declarations:
Subclause [cwchar.syn] describes the changes.
Header <cstddef> declares the names nullptr_t, byte, and to_integer, and the operators and operator templates in ([support.types.byteops]), in addition to the names declared in <stddef.h> in the C standard library.

C.8.5 Modifications to behavior [diff.mods.to.behavior]

C.8.5.1 General [diff.mods.to.behavior.general]

Header <cstdlib>: The following functions have different behavior:
Subclause [support.start.term] describes the changes.
Header <csetjmp>: The following functions have different behavior:
Subclause [csetjmp.syn] describes the changes.

C.8.5.2 Macro offsetof(type, member-designator) [diff.offsetof]

The macro offsetof, defined in <cstddef>, accepts a restricted set of type arguments in C++.
Subclause [support.types.layout] describes the change.

C.8.5.3 Memory allocation functions [diff.malloc]

The functions aligned_alloc, calloc, malloc, and realloc are restricted in C++.
Subclause [c.malloc] describes the changes.