int function( int i ); int function( char c ); function( 'x' );
sizeof('x') == sizeof(int)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;
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++
}
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 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++
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 {
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++
};
struct X { int i; };
volatile struct X x1 = {0};
struct X x2 = x1; // invalid C++
struct X x3;
x3 = x1; // also invalid C++
#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
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
}
#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 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);
}
namespace N {
struct X {};
bool operator<=(X, X);
template<bool(X, X)> struct Y {};
Y<operator<=> y; // ill-formed; previously well-formed
}
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
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 A {};
bool operator<(void (*fp)(), A);
void f() {}
int main() {
A a;
f < a; // ill-formed; previously well-formed
(f) < a; // still well formed
}