class module {}; module m1; // was variable declaration; now module-declaration module *m2; // variable declaration class import {}; import j1; // was variable declaration; now import-declaration ::import j2; // variable declaration— end example
template<typename> class import {}; import<int> f(); // ill-formed; previously well-formed ::import<int> g(); // OK— end example
namespace N { struct X {}; bool operator<=(X, X); template<bool(X, X)> struct Y {}; Y<operator<=> y; // ill-formed; previously well-formed }
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.
int f() { int a = 123; using T = int; a.~T(); return a; // undefined behavior; previously returned 123 }— end example
typedef struct { void f() {} // ill-formed; previously well-formed } S;
// 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
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
bool y[] = { "bc" }; // ill-formed; previously well-formed
struct S { explicit (S)(const S&); // ill-formed; previously well-formed explicit (operator int)(); // ill-formed; previously well-formed explicit(true) (S)(int); // OK };
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 };
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 }
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 }
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 }
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
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
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
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
#define F(a) b ## a int b0p = F(0p+0); // ill-formed; equivalent to “int b0p = b0p + 0;” in C++ 2014
auto x1{1}; // was std::initializer_list<int>, now int auto x2{1, 2}; // was std::initializer_list<int>, now ill-formed
void g1() noexcept; void g2(); template<class T> int f(T *, T *); int x = f(g1, g2); // ill-formed; previously well-formed
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
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).
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 }
#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*
int f(char *) = delete; int f(const char *); string s; int x = f(s.data()); // ill-formed; previously well-formed
#include <set> struct compare { bool operator()(int a, int b) { return a < b; } }; int main() { const std::set<int, compare> s; s.find(0); }
#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 International Standard
void* operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept;
struct S { int x = 1; void mf() { x = 2; } }; int f(bool cond) { S s; (cond ? s : throw 0).mf(); return s.x; }
sizeof(true ? "" : throw 0)
struct S { constexpr const int &f(); int &f(); };
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 International Standard
#define u8 "abc" const char* s = u8"def"; // Previously "abcdef", now "def"
#define _x "there" "hello"_x // #1
void f(void *); // #1 void f(...); // #2 template<int N> void g() { f(0*N); // calls #2; used to call #1 }
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
int x[] = { 2.0 };
template <class T> struct X { }; template <int N> struct Y { }; X< Y< 1 >> 2 > > x;
#include <iostream> int main() { int flag = std::ios_base::hex; std::cout.setf(flag); // error: setf does not take argument of type int }
int function( int i ); int function( char c ); function( 'x' );
sizeof('x') == sizeof(int)will not work the same as C++ programs.
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 }
int i; int i;is valid in C, invalid in C++.
struct X { int i; struct X* next; }; static struct X a; static struct X b = { 0, &a }; static struct X a = { 1, &b };
char a[10]; void* b=a; void foo() { char* c=b; }
char* c = (char*) b;
char arr[100]; sizeof(0, arr)
static struct S { // valid C, invalid in C++ int i; };
typedef struct name1 { /* ... */ } name1; // valid C and C++ struct name { /* ... */ }; typedef int name; // valid C, invalid C++
class name { /* ... */ }; name i; // i has type class name
void f(const parm); void f(const int parm); const n = 3; const int n = 3; main() int main() /* ... */ /* ... */
void f() { auto int x; // valid C, invalid C++ }
int f(); // means int f(void) in C++ // int f( unknown ) in C
void f( struct S { int a; } arg ) {} // valid C, invalid C++ enum E { A, B, C } f() {} // valid C, invalid C++
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++
char array[4] = "abcd"; // valid C, invalid C++
enum color { red, blue, green }; enum color c = 1; // valid C, invalid C++
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) */
int x[99]; void f() { struct x { int a; }; sizeof(x); /* size of the array in C */ /* size of the struct 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++
struct X { struct Y { /* ... */ } y; }; struct Y yy; // valid C, invalid C++
struct Y; // struct Y and struct X are at the same scope struct X { struct Y { /* ... */ } y; };
typedef int I; struct S { I i; int I; // valid C, invalid C++ };