Annex C (informative) Compatibility [diff]

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

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++.
For example: struct S { explicit (S)(const S&); // ill-formed; previously well-formed explicit (operator int)(); // ill-formed; previously well-formed explicit(true) (S)(int); // OK };
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++.
For example: 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 };
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++.
For example: 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 }