struct S { int n; };
auto f() {
  S x { 1 };
  constexpr S y { 2 };
  return [&](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false);   // undefined behavior due to access of x.n outside its lifetime
int n = g(true);    // OK, does not access y.n
 — end example
struct X { int n; };
int k = X().n;      // OK, X() prvalue is converted to xvalue
 — end example
int main() {
  const char c = 'c';
  char* pc;
  const char** pcc = &pc;       // #1: not allowed
  *pcc = &c;
  *pc = 'C';                    // #2: modifies a const object
} — end notevoid (*p)(); void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function struct S { typedef void (*p)(); operator p(); }; void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function— end example
primary-expression: literal this ( expression ) id-expression lambda-expression fold-expression requires-expression
struct A {
  char g();
  template<class T> auto f(T t) -> decltype(t + g())
    { return t + g(); }
};
template auto A::f(int t) -> decltype(t + g()); — end example
class Outer {
  int a[sizeof(*this)];               // error: not inside a member function
  unsigned int sz = sizeof(*this);    // OK: in default member initializer
  void f() {
    int b[sizeof(*this)];             // OK
    struct Inner {
      int c[sizeof(*this)];           // error: not inside a member function of Inner
    };
  }
}; — end exampleid-expression: unqualified-id qualified-id
struct S {
  int m;
};
int i = sizeof(S::m);           // OK
int j = sizeof(S::m + 42);      // OK
 — end example
void f(int) requires false;
void g() {
  f(0);                         // error: cannot call f
  void (*p1)(int) = f;          // error: cannot take the address of f
  decltype(f)* p2 = nullptr;    // error: the type decltype(f) is invalid
} unqualified-id: identifier operator-function-id conversion-function-id literal-operator-id ~ class-name ~ decltype-specifier template-id
void f() {
  float x, &r = x;
  [=] {
    decltype(x) y1;             // y1 has type float
    decltype((x)) y2 = y1;      // y2 has type float const& because this lambda
                                // is not mutable and x is an lvalue
    decltype(r) r1 = y1;        // r1 has type float&
    decltype((r)) r2 = y2;      // r2 has type float const&
  };
} — end examplequalified-id: nested-name-specifier template unqualified-id
nested-name-specifier: :: type-name :: namespace-name :: decltype-specifier :: nested-name-specifier identifier :: nested-name-specifier template simple-template-id ::
lambda-expression: lambda-introducer compound-statement lambda-introducer lambda-declarator requires-clause compound-statement lambda-introducer < template-parameter-list > requires-clause compound-statement lambda-introducer < template-parameter-list > requires-clause lambda-declarator requires-clause compound-statement
lambda-introducer: [ lambda-capture ]
lambda-declarator: ( parameter-declaration-clause ) decl-specifier-seq noexcept-specifier attribute-specifier-seq trailing-return-type
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
  std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });
} — end example
auto x1 = [](int i){ return i; };     // OK: return type is int
auto x2 = []{ return { 1, 2 }; };     // error: deducing return type from braced-init-list
int j;
auto x3 = []()->auto&& { return j; }; // OK: return type is int&
 — end example
int i = [](int i, auto a) { return i; }(3, 4);         // OK: a generic lambda
int j = []<class T>(T t, int i) { return i; }(3, 4);   // OK: a generic lambda
 — end example
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14);                             // OK
auto vglambda = [](auto printer) {
  return [=](auto&& ... ts) {                          // OK: ts is a function parameter pack
    printer(std::forward<decltype(ts)>(ts)...);
    return [=]() {
      printer(ts ...);
    };
  };
};
auto p = vglambda( [](auto v1, auto v2, auto v3)
                   { std::cout << v1 << v2 << v3; } );
auto q = p(1, 'a', 3.14);                              // OK: outputs 1a3.14
q();                                                   // OK: outputs 1a3.14
 — end example
auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK
struct NonLiteral {
  NonLiteral(int n) : n(n) { }
  int n;
};
static_assert(ID(NonLiteral{3}).n == 3); // ill-formed
 — end example
auto monoid = [](auto v) { return [=] { return v; }; };
auto add = [](auto m1) constexpr {
  auto ret = m1();
  return [=](auto m2) mutable {
    auto m1val = m1();
    auto plus = [=](auto m2val) mutable constexpr
                   { return m1val += m2val; };
    ret = plus(m2());
    return monoid(ret);
  };
};
constexpr auto zero = monoid(0);
constexpr auto one = monoid(1);
static_assert(add(one)(zero)() == one()); // OK
// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
// in a constant expression.
auto two = monoid(2);
assert(two() == 2); // OK, not a constant expression.
static_assert(add(one)(one)() == two()); // ill-formed: two() is not a constant expression
static_assert(add(one)(one)() == monoid(2)()); // OK
 — end exampletemplate <typename T> concept C1 = /* ... */; template <std::size_t N> concept C2 = /* ... */; template <typename A, typename B> concept C3 = /* ... */; auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)> (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> { // T2 is a constrained parameter, // T1 and T2 are constrained by a requires-clause, and // T2 and the type of a4 are constrained by a trailing requires-clause. };— end example
auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;
The behavior of the conversion function of glambda above is like
that of the following conversion function:
struct Closure {
  template<class T> auto operator()(T t) const { /* ... */ }
  template<class T> static auto lambda_call_operator_invoker(T a) {
    // forwards execution to operator()(a) and therefore has
    // the same return type deduced
    /* ... */
  }
  template<class T> using fptr_t =
     decltype(lambda_call_operator_invoker(declval<T>())) (*)(T);
  template<class T> operator fptr_t<T>() const
    { return &lambda_call_operator_invoker; }
};
void f1(int (*)(int))   { }
void f2(char (*)(int))  { }
void g(int (*)(int))    { }  // #1
void g(char (*)(char))  { }  // #2
void h(int (*)(int))    { }  // #3
void h(char (*)(int))   { }  // #4
auto glambda = [](auto a) { return a; };
f1(glambda);  // OK
f2(glambda);  // error: ID is not convertible
g(glambda);   // error: ambiguous
h(glambda);   // OK: calls #3 since it is convertible from ID
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
 — end example
auto GL = [](auto a) { std::cout << a; return a; };
int (*GL_int)(int) = GL;  // OK: through conversion function template
GL_int(3);                // OK: same as GL(3)
 — end example
auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };
static_assert(Fwd(C,3) == 3); // OK
// No specialization of the function call operator template can be constexpr (due to the local static).
auto NC = [](auto a) { static int s; return a; };
static_assert(Fwd(NC,3) == 3); // ill-formed
 — end example
struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)
                                      // this has type S1*
    };
  }
}; — end examplelambda-capture: capture-default capture-list capture-default , capture-list
capture-default: & =
capture-list: capture capture-list , capture
capture: simple-capture ... ... init-capture
simple-capture: identifier & identifier this * this
init-capture: identifier initializer & identifier initializer
struct S2 { void f(int i); };
void S2::f(int i) {
  [&, i]{ };        // OK
  [&, this, i]{ };  // OK, equivalent to [&, i]
  [&, &i]{ };       // error: i preceded by & when & is the default
  [=, *this]{ };    // OK
  [=, this]{ };     // OK, equivalent to [=]
  [i, i]{ };        // error: i repeated
  [this, *this]{ }; // error: this appears twice
} — end example
void f() {
  int x = 0;
  auto g = [x](int x) { return 0; }    // error: parameter and simple-capture have the same name
} — end example
int x = 4;
auto y = [&r = x, x = x+1]()->int {
            r += 2;
            return x+2;
         }();  // Updates ::x to 6, and initializes y to 7.
auto z = [a = 42](int a) { return 1; } // error: parameter and local variable have the same name
 — end example
void f(int, const int (&)[2] = {});         // #1
void f(const int&, const int (&)[1]);       // #2
void test() {
  const int x = 17;
  auto g = [](auto a) {
    f(x);                       // OK: calls #1, does not capture x
  };
  auto g1 = [=](auto a) {
    f(x);                       // OK: calls #1, captures x
  };
  auto g2 = [=](auto a) {
    int selector[sizeof(a) == 1 ? 1 : 2]{};
    f(x, selector);             // OK: captures x, might call #1 or #2
  };
  auto g3 = [=](auto a) {
    typeid(a + x);              // captures x regardless of whether a + x is an unevaluated operand
  };
}  — end example
template<bool B>
void f(int n) {
  [=](auto a) {
    if constexpr (B && sizeof(a) > 4) {
      (void)n;                  // captures n regardless of the value of B and sizeof(int)
    }
  }(0);
} — end example
void f1(int i) {
  int const N = 20;
  auto m1 = [=]{
    int const M = 30;
    auto m2 = [i]{
      int x[N][M];          // OK: N and M are not odr-used
      x[0][0] = i;          // OK: i is explicitly captured by m2 and implicitly captured by m1
    };
  };
  struct s1 {
    int f;
    void work(int n) {
      int m = n*n;
      int j = 40;
      auto m3 = [this,m] {
        auto m4 = [&,j] {   // error: j not odr-usable due to intervening lambda m3
          int x = n;        // error: n is odr-used but not odr-usable due to intervening lambda m3
          x += m;           // OK: m implicitly captured by m4 and explicitly captured by m3
          x += i;           // error: i is odr-used but not odr-usable
                            // due to intervening function and class scopes
          x += f;           // OK: this captured implicitly by m4 and explicitly by m3
        };
      };
    }
  };
}
struct s2 {
  double ohseven = .007;
  auto f() {
    return [this] {
      return [*this] {
          return ohseven;   // OK
      }
    }();
  }
  auto g() {
    return [] {
      return [*this] { };   // error: *this not captured by outer lambda-expression
    }();
  }
}; — end example
void f2() {
  int i = 1;
  void g1(int = ([i]{ return i; })());          // ill-formed
  void g2(int = ([i]{ return 0; })());          // ill-formed
  void g3(int = ([=]{ return i; })());          // ill-formed
  void g4(int = ([=]{ return 0; })());          // OK
  void g5(int = ([]{ return sizeof i; })());    // OK
} — end example
void f(const int*);
void g() {
  const int N = 10;
  [=] {
    int arr[N];     // OK: not an odr-use, refers to automatic variable
    f(&N);          // OK: causes N to be captured; &N points to
                    // the corresponding member of the closure type
  };
} — end example
// The inner closure type must be a literal type regardless of how reference captures are represented.
static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4); — end example
auto h(int &r) {
  return [&] {
    ++r;            // Valid after h returns if the lifetime of the
                    // object to which r is bound has not ended
  };
} — end example
int a = 1, b = 1, c = 1;
auto m1 = [a, &b, &c]() mutable {
  auto m2 = [a, b, &c]() mutable {
    std::cout << a << b << c;
    a = 4; b = 4; c = 4;
  };
  a = 3; b = 3; c = 3;
  m2();
};
a = 2; b = 2; c = 2;
m1();
std::cout << a << b << c; — end example
template<class... Args>
void f(Args... args) {
  auto lm = [&, args...] { return g(args...); };
  lm();
  auto lm2 = [...xs=std::move(args)] { return g(xs...); };
  lm2();
} — end examplefold-expression: ( cast-expression fold-operator ... ) ( ... fold-operator cast-expression ) ( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of + - * / % ^ & | << >> += -= *= /= %= ^= &= |= <<= >>= = == != < > <= >= && || , .* ->*
template<typename ...Args>
bool f(Args ...args) {
  return (true && ... && args); // OK
}
template<typename ...Args>
bool f(Args ...args) {
  return (args + ... + args);   // error: both operands contain unexpanded packs
} — end examplerequires-expression: requires requirement-parameter-list requirement-body
requirement-parameter-list: ( parameter-declaration-clause )
requirement-body: { requirement-seq }
requirement-seq: requirement requirement-seq requirement
requirement: simple-requirement type-requirement compound-requirement nested-requirement
template<typename T>
  concept R = requires (T i) {
    typename T::type;
    {*i} -> const typename T::type&;
  };
A requires-expression can also be used in a
requires-clause as a way of writing ad hoc
constraints on template arguments such as the one below:
template<typename T>
  requires requires (T x) { x + x; }
    T add(T a, T b) { return a + b; }
The first requires introduces the
requires-clause, and the second
introduces the requires-expression.
template<typename T>
concept C = requires(T t, ...) {    // error: terminates with an ellipsis
  t;
}; — end example
template<typename T> concept C =
requires {
  new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required
}; — end examplesimple-requirement: expression ;
template<typename T> concept C =
  requires (T a, T b) {
    a + b;  // C<T> is true if a + b is a valid expression
  }; — end exampletype-requirement: typename nested-name-specifier type-name ;
template<typename T, typename T::type = 0> struct S;
template<typename T> using Ref = T&;
template<typename T> concept C = requires {
  typename T::inner;    // required nested member name
  typename S<T>;        // required class template specialization
  typename Ref<T>;      // required alias template substitution, fails if T is void
}; — end examplecompound-requirement: { expression } noexcept return-type-requirement ;
return-type-requirement: trailing-return-type -> cv-qualifier-seq constrained-parameter cv-qualifier-seq abstract-declarator
template<typename T> concept C1 = requires(T x) {
  {x++};
};  
template<typename T> concept C2 = requires(T x) {
  {*x} -> typename T::inner;
};
template<typename T, typename U> concept C3 = requires (T t, U u) {
  t == u;
};
template<typename T> concept C4 = requires(T x) {
  {*x} -> C3<int> const&;
}; template<C3<int> X> void f(X const&);In this case, deduction only succeeds if an expression of the type deduced for X can be compared to an int with the == operator.
template<typename T> concept C5 =
  requires(T x) {
    {g(x)} noexcept;
  };nested-requirement: requires constraint-expression ;
template<typename U> concept C = sizeof(U) == 1;
template<typename T> concept D = requires (T t) {
  requires C<decltype (+t)>;
};  — end example
template<typename T> concept C = requires (T a) {
  requires sizeof(a) == 4;  // OK
  requires a == 0;          // error: evaluation of a constraint variable
} — end examplepostfix-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
constant-expression: conditional-expression
void g() {
  const int n = 0;
  [=] {
    constexpr int i = n;   // OK, n is not odr-used here
    constexpr int j = *&n; // ill-formed, &n would be an odr-use of n
  };
} — end example
auto monad = [](auto v) { return [=] { return v; }; };
auto bind = [](auto m) {
  return [=](auto fvm) { return fvm(m()); };
};
// OK to have captures to automatic objects created during constant expression evaluation.
static_assert(bind(monad(2))(monad)() == monad(2)()); — end exampleint x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK: constructor call initializes m with the value 42 constexpr int w = A(false).m; // error: initializer for m is x, which is non-constant constexpr int f1(int k) { constexpr int x = k; // error: x is not initialized by a constant expression // because lifetime of k began outside the initializer of x return x; } constexpr int f2(int k) { int x = k; // OK: not required to be a constant expression // because x is not constexpr return x; } constexpr int incr(int &n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // error: incr(k) is not a core constant expression // because lifetime of k began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside h(1)— end example
struct A {
  constexpr A(int i) : val(i) { }
  constexpr operator int() const { return val; }
  constexpr operator long() const { return 42; }
private:
  int val;
};
template<int> struct X { };
constexpr A a = alignof(int);
alignas(a) int n;              // error: ambiguous conversion
struct B { int n : a; };       // error: ambiguous conversion
 — end example
bool f() {
    char array[1 + int(1 + 0.2 - 0.1 - 0.1)];  // Must be evaluated during translation
    int size = 1 + int(1 + 0.2 - 0.1 - 0.1);   // May be evaluated at runtime
    return sizeof(array) == size;
}  — end example