postfix-expression: primary-expression postfix-expression [ expr-or-braced-init-list ] postfix-expression ( expression-list ) simple-type-specifier ( expression-list ) typename-specifier ( expression-list ) simple-type-specifier braced-init-list typename-specifier braced-init-list postfix-expression . template id-expression postfix-expression -> template id-expression postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name postfix-expression ++ postfix-expression -- dynamic_cast < type-id > ( expression ) static_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) const_cast < type-id > ( expression ) typeid ( expression ) typeid ( type-id )
expression-list: initializer-list
pseudo-destructor-name: nested-name-specifier type-name :: ~ type-name nested-name-specifier template simple-template-id :: ~ type-name ~ type-name ~ decltype-specifier
template<typename ...T> int f(int n = 0, T ...t);
int x = f<int>(); // error: no argument for second function parameter
— end example
void f() {
std::string s = "but I have heard it works even if you don't believe in it";
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");
assert(s == "I have heard it works only if you believe in it"); // OK
} — end example
struct S {
S(int);
};
int operator<<(S, int);
int i, j;
int x = S(i=1) << (i=2);
int y = operator<<(S(j=1), j=2); nested-name-specifier type-name :: ~ type-nameshall designate the same scalar type (ignoring cv-qualification).
struct B { };
struct D : B { };
void foo(D* dp) {
B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
} — end example
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
D d;
B* bp = (B*)&d; // cast needed to break protection
A* ap = &d; // public derivation, no cast needed
D& dr = dynamic_cast<D&>(*bp); // fails
ap = dynamic_cast<A*>(bp); // fails
bp = dynamic_cast<B*>(ap); // fails
ap = dynamic_cast<A*>(&d); // succeeds
bp = dynamic_cast<B*>(&d); // ill-formed (not a runtime check)
}
class E : public D, public B { };
class F : public E, public D { };
void h() {
F f;
A* ap = &f; // succeeds: finds unique A
D* dp = dynamic_cast<D*>(ap); // fails: yields null; f has two D subobjects
E* ep = (E*)ap; // ill-formed: cast from virtual base
E* ep1 = dynamic_cast<E*>(ap); // succeeds
} — end example
class D { /* ... */ };
D d1;
const D d2;
typeid(d1) == typeid(d2); // yields true
typeid(D) == typeid(const D); // yields true
typeid(D) == typeid(d2); // yields true
typeid(D) == typeid(const D&); // yields true
— end example
struct B { };
struct D : public B { };
D d;
B &br = d;
static_cast<D&>(br); // produces lvalue to the original d object
— end exampleT t(e);for some invented temporary variable t ([dcl.init]) and then using the temporary variable as the result of the conversion.
struct B { };
struct D : private B { };
void f() {
static_cast<D*>((B*)0); // error: B is a private base of D
static_cast<int B::*>((int D::*)0); // error: B is a private base of D
} — end example
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.
— end exampletypedef int *A[3]; // array of 3 pointer to int typedef const int *const CA[3]; // array of 3 const pointer to const int CA &&r = A{}; // OK, reference binds to temporary array object after qualification conversion to type CA A &&r1 = const_cast<A>(CA{}); // error: temporary array decayed to pointer A &&r2 = const_cast<A&&>(CA{}); // OK— end example
unary-expression: postfix-expression ++ cast-expression -- cast-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-id ) sizeof ... ( identifier ) alignof ( type-id ) noexcept-expression new-expression delete-expression
unary-operator: one of * & + - ! ~
struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*
int a;
int* p1 = &a;
int* p2 = p1 + 1; // defined behavior
bool b = p2 > p1; // defined behavior, with value true
— end example
template<class... Types>
struct count {
static const std::size_t value = sizeof...(Types);
}; — end examplenew-expression: :: new new-placement new-type-id new-initializer :: new new-placement ( type-id ) new-initializer
new-placement: ( expression-list )
new-type-id: type-specifier-seq new-declarator
new-declarator: ptr-operator new-declarator noptr-new-declarator
noptr-new-declarator: [ expression ] attribute-specifier-seq noptr-new-declarator [ constant-expression ] attribute-specifier-seq
new-initializer: ( expression-list ) braced-init-list
T x init ;new auto(1); // allocated type is int auto x = new auto('a'); // allocated type is char, x is of type char* template<class T> struct A { A(T, T); }; auto y = new A{1, 2}; // allocated type is A<int>— end example
new int(*[10])(); // error
(new int) (*[10])(); // error
new (int (*[10])());allocates an array of 10 pointers to functions (taking no argument and returning int).
void mergeable(int x) {
// These allocations are safe for merging:
std::unique_ptr<char[]> a{new (std::nothrow) char[8]};
std::unique_ptr<char[]> b{new (std::nothrow) char[8]};
std::unique_ptr<char[]> c{new (std::nothrow) char[x]};
g(a.get(), b.get(), c.get());
}
void unmergeable(int x) {
std::unique_ptr<char[]> a{new char[8]};
try {
// Merging this allocation would change its catch handler.
std::unique_ptr<char[]> b{new char[x]};
} catch (const std::bad_alloc& e) {
std::cerr << "Allocation failed: " << e.what() << std::endl;
throw;
}
} — end exampleoperator new(sizeof(T)) operator new(sizeof(T), std::align_val_t(alignof(T)))
operator new(sizeof(T), 2, f) operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
operator new[](sizeof(T) * 5 + x) operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)))
operator new[](sizeof(T) * 5 + x, 2, f) operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)), 2, f)
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function matches
// placement allocation function
— end exampledelete-expression: :: delete cast-expression :: delete [ ] cast-expression
noexcept-expression: noexcept ( expression )
cast-expression: unary-expression ( type-id ) cast-expression
struct A { };
struct I1 : A { };
struct I2 : A { };
struct D : I1, I2 { };
A* foo( D* p ) {
return (A*)( p ); // ill-formed static_cast interpretation
} — end example
struct S {
S() : i(0) { }
mutable int i;
};
void f()
{
const S cs;
int S::* pm = &S::i; // pm refers to mutable member S::i
cs.*pm = 88; // ill-formed: cs is a const object
} — end notemultiplicative-expression: pm-expression multiplicative-expression * pm-expression multiplicative-expression / pm-expression multiplicative-expression % pm-expression
additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression
shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression
compare-expression: shift-expression compare-expression <=> shift-expression
relational-expression: compare-expression relational-expression < compare-expression relational-expression > compare-expression relational-expression <= compare-expression relational-expression >= compare-expressionThe lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) standard conversions are performed on the operands.
equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression
struct A {};
struct B : A { int x; };
struct C : A { int x; };
int A::*bx = (int(A::*))&B::x;
int A::*cx = (int(A::*))&C::x;
bool b1 = (bx == cx); // unspecified
— end example
struct B {
int f();
};
struct L : B { };
struct R : B { };
struct D : L, R { };
int (B::*pb)() = &B::f;
int (L::*pl)() = pb;
int (R::*pr)() = pb;
int (D::*pdl)() = pl;
int (D::*pdr)() = pr;
bool x = (pdl == pdr); // false
bool y = (pb == pl); // true
— end exampleand-expression: equality-expression and-expression & equality-expression
exclusive-or-expression: and-expression exclusive-or-expression ^ and-expression
inclusive-or-expression: exclusive-or-expression inclusive-or-expression | exclusive-or-expression
logical-and-expression: inclusive-or-expression logical-and-expression && inclusive-or-expression
logical-or-expression: logical-and-expression logical-or-expression || logical-and-expression
conditional-expression: logical-or-expression logical-or-expression ? expression : assignment-expression
throw-expression: throw assignment-expression
try {
// ...
} catch (...) { // catch all exceptions
// respond (partially) to exception
throw; // pass the exception to some other handler
}assignment-expression: conditional-expression logical-or-expression assignment-operator initializer-clause throw-expression
assignment-operator: one of = *= /= %= += -= >>= <<= &= ^= |=
complex<double> z;
z = { 1,2 }; // meaning z.operator=({1,2})
z += { 1, 2 }; // meaning z.operator+=({1,2})
int a, b;
a = b = { 1 }; // meaning a=b=1;
a = { 1 } = b; // syntax error
— end exampleexpression: assignment-expression expression , assignment-expression