13 KiB
[stmt.iter]
8 Statements [stmt]
8.6 Iteration statements [stmt.iter]
8.6.1 General [stmt.iter.general]
Iteration statements specify looping.
iteration-statement:
while ( condition ) statement
do statement while ( expression ) ;
for ( init-statement conditionopt ; expressionopt ) statement
for ( init-statementopt for-range-declaration : for-range-initializer ) statement
[Note 1:
An init-statement ends with a semicolon.
â end note]
The substatement in an iteration-statement implicitly defines a block scope which is entered and exited each time through the loop.
If the substatement in an iteration-statement is a single statement and not a compound-statement, it is as if it was rewritten to be a compound-statement containing the original statement.
[Example 1:
while (--x >= 0)int i; can be equivalently rewritten aswhile (--x >= 0) {int i;}
Thus after the while statement, i is no longer in scope.
â end example]
A trivially empty iteration statement is an iteration statement matching one of the following forms:
while ( expression ) ;
while ( expression ) { }
do ; while ( expression ) ;
do { } while ( expression ) ;
for ( init-statement expressionopt ; ) ;
for ( init-statement expressionopt ; ) { }
The controlling expression of a trivially empty iteration statement is the expression of a while, do, or for statement (or true, if the for statement has no expression).
A trivial infinite loop is a trivially empty iteration statement for which the converted controlling expression is a constant expression, when interpreted as a constant-expression ([expr.const]), and evaluates to true.
The statement of a trivial infinite loop is replaced with a call to the function std::this_thread::yield ([thread.thread.this]); it is implementation-defined whether this replacement occurs on freestanding implementations.
[Note 2:
In a freestanding environment, concurrent forward progress is not guaranteed; such systems therefore require explicit cooperation.
A call to yield can add implicit cooperation where none is otherwise intended.
â end note]
8.6.2 The while statement [stmt.while]
In the while statement, the substatement is executed repeatedly until the value of the condition ([stmt.pre]) becomesfalse.
The test takes place before each execution of the substatement.
A while statement is equivalent to
label :
{
if ( condition ) {
statement
goto label ;
}
}
[Note 1:
The variable created in the condition is destroyed and created with each iteration of the loop.
[Example 1: 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]
â end note]
8.6.3 The do statement [stmt.do]
The expression is contextually converted to bool; if that conversion is ill-formed, the program is ill-formed.
In the do statement, the substatement is executed repeatedly until the value of the expression becomes false.
The test takes place after each execution of the statement.
8.6.4 The for statement [stmt.for]
The for statement
for ( init-statement conditionopt ; expressionopt ) statement
is equivalent to
{
init-statement
while ( condition ) {
statement
expression ;
}
}
except that the init-statement is in the same scope as the condition, and except that acontinue in statement (not enclosed in another iteration statement) will execute expression before re-evaluating condition.
[Note 1:
Thus the first statement specifies initialization for the loop; the condition ([stmt.pre]) specifies a test, sequenced before each iteration, such that the loop is exited when the condition becomesfalse; the expression often specifies incrementing that is sequenced after each iteration.
â end note]
Either or both of the condition and the expression can be omitted.
A missing condition makes the implied while clause equivalent to while (true).
8.6.5 The range-based for statement [stmt.ranged]
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer ) statement
is equivalent to
{
init-statementopt
auto &&range = for-range-initializer ;
auto begin = begin-expr ;
auto end = end-expr ;
for ( ; begin != end; ++begin ) {
for-range-declaration = * begin ;
statement
}
}
where
if the for-range-initializer is an expression, it is regarded as if it were surrounded by parentheses (so that a comma operator cannot be reinterpreted as delimiting two init-declarators);
range, begin, and end are variables defined for exposition only; and
begin-expr and end-expr are determined as follows:
-
if the type of range is a reference to an array type R, begin-expr and end-expr arerange and range + N, respectively, where N is the array bound. If R is an array of unknown bound or an array of incomplete type, the program is ill-formed;
-
if the type of range is a reference to a class type C, and searches in the scope of C ([class.member.lookup]) for the names begin and end each find at least one declaration,begin-expr and end-expr arerange.begin() and range.end(), respectively;
-
otherwise, begin-expr and end-expr arebegin(range) and end(range), respectively, where begin and end undergo argument-dependent lookup ([basic.lookup.argdep]). [Note 1: Ordinary unqualified lookup ([basic.lookup.unqual]) is not performed. â end note]
[Example 1: int array[5] = { 1, 2, 3, 4, 5 };for (int& x : array) x *= 2; â end example]
[Note 2:
The lifetime of some temporaries in the for-range-initializer is extended to cover the entire loop ([class.temporary]).
â end note]
[Example 2: using T = std::list;const T& f1(const T& t) { return t; }const T& f2(T t) { return t; } T g();
void foo() {for (auto e : f1(g())) {} // OK, lifetime of return value of g() extendedfor (auto e : f2(g())) {} // undefined behavior} â end example]