statement: labeled-statement attribute-specifier-seq expression-statement attribute-specifier-seq compound-statement attribute-specifier-seq selection-statement attribute-specifier-seq iteration-statement attribute-specifier-seq jump-statement declaration-statement attribute-specifier-seq try-block init-statement: expression-statement simple-declaration condition: expression attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializer
labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statement
expression-statement: expression ;
compound-statement: { statement-seq }
statement-seq: statement statement-seq statement
selection-statement: if constexpr ( init-statement condition ) statement if constexpr ( init-statement condition ) statement else statement switch ( init-statement condition ) statement
template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) { // ... handle p if constexpr (sizeof...(rs) > 0) g(rs...); // never instantiated with an empty argument list } extern int x; // no definition of x required int f() { if constexpr (true) return 0; else if (x) return x; else return -x; }— end example
if constexpr ( init-statement condition ) statementis equivalent to
{ init-statement if constexpr ( condition ) statement }and an if statement of the form
if constexpr ( init-statement condition ) statement else statementis equivalent to
{ init-statement if constexpr ( condition ) statement else statement }except that names declared in the init-statement are in the same declarative region as those declared in the condition.
case constant-expression :where the constant-expression shall be a converted constant expression of the adjusted type of the switch condition.
switch ( init-statement condition ) statementis equivalent to
{ init-statement switch ( condition ) statement }except that names declared in the init-statement are in the same declarative region as those declared in the condition.
iteration-statement: while ( condition ) statement do statement while ( expression ) ; for ( init-statement condition ; expression ) statement for ( init-statement for-range-declaration : for-range-initializer ) statement
for-range-declaration: attribute-specifier-seq decl-specifier-seq declarator attribute-specifier-seq decl-specifier-seq ref-qualifier [ identifier-list ]
for-range-initializer: expr-or-braced-init-list
void f() { for (int i = 0; i < 10; ++i) int i = 0; // error: redeclaration for (int i : { 1, 2, 3 }) int i = 1; // error: redeclaration }— end example
label : { if ( condition ) { statement goto label ; } }
struct A { int val; A(int i) : val(i) { } ~A() { } operator bool() { return val != 0; } }; int i = 1; while (A a = i) { // ... i = 0; }In the while-loop, the constructor and destructor are each called twice, once for the condition that succeeds and once for the condition that fails. — end example
for ( init-statement condition ; expression ) statementis equivalent to
{ init-statement while ( condition ) { statement expression ; } }except that names declared in the init-statement are in the same declarative region as those declared in the condition, and except that a continue in statement (not enclosed in another iteration statement) will execute expression before re-evaluating condition.
int i = 42; int a[10]; for (int i = 0; i < 10; i++) a[i] = i; int j = i; // j = 42— end example
for ( init-statement for-range-declaration : for-range-initializer ) statementis equivalent to
{ init-statement auto &&range = for-range-initializer ; auto begin = begin-expr ; auto end = end-expr ; for ( ; begin != end; ++begin ) { for-range-declaration = * begin ; statement } }where
int array[5] = { 1, 2, 3, 4, 5 }; for (int& x : array) x *= 2;— end example
jump-statement: break ; continue ; return expr-or-braced-init-list ; coroutine-return-statement goto identifier ;
while (foo) { { // ... } contin: ; }
do { { // ... } contin: ; } while (foo);
for (;;) { { // ... } contin: ; }
std::pair<std::string,int> f(const char* p, int x) { return {p,x}; }— end example
class A { ~A() {} }; A f() { return A(); } // error: destructor of A is private (even though it is never invoked)— end example
coroutine-return-statement: co_return expr-or-braced-init-list ;
{ S; goto final-suspend; }where final-suspend is the exposition-only label defined in [dcl.fct.def.coroutine] and S is defined as follows:
declaration-statement: block-declaration
void f() { // ... goto lx; // error: jump into scope of a // ... ly: X a = 1; // ... lx: goto ly; // OK, jump implies destructor call for a followed by // construction again immediately following label ly }— end example
int foo(int i) { static int s = foo(2*i); // undefined behavior: recursive call return i+1; }— end example
T(a)->m = 7; // expression-statement T(a)++; // expression-statement T(a,5)<<c; // expression-statement T(*d)(int); // declaration T(e)[5]; // declaration T(f) = { 1, 2 }; // declaration T(*g)(double(3)); // declaration
class T { // ... public: T(); T(int); T(int, int); }; T(a); // declaration T(*b)(); // declaration T(c)=7; // declaration T(d),e,f=3; // declaration extern int h; T(g)(h,2); // declaration— end example
struct T1 { T1 operator()(int x) { return T1(x); } int operator=(int x) { return x; } T1(int) { } }; struct T2 { T2(int){ } }; int a, (*(*b)(T2))(int), c, d; void f() { // disambiguation requires this to be parsed as a declaration: T1(a) = 3, T2(4), // T2 will be declared as a variable of type T1, but this will not (*(*b)(T2(c)))(int(d)); // allow the last part of the declaration to parse properly, // since it depends on T2 being a type-name }— end example