8.1 KiB
[stmt.expand]
8 Statements [stmt]
8.7 Expansion statements [stmt.expand]
Expansion statements specify repeated instantiations ([temp.decls.general]) of their substatement.
expansion-statement:
template for (init-statementopt for-range-declaration :expansion-initializer ) compound-statement
expansion-initializer:
expression
expansion-init-list
expansion-init-list:
{ expression-listopt }
The compound-statement of an expansion-statement is a control-flow-limited statement ([stmt.label]).
For an expression E, let the expressionsbegin-expr and end-expr be determined as specified in [stmt.ranged].
An expression is expansion-iterable if it does not have array type and either
begin-expr and end-expr are of the formE.begin() and E.end(), or
argument-dependent lookups for begin(E) and for end(E) each find at least one function or function template.
An expansion statement is
an enumerating expansion statement if its expansion-initializer is of the form expansion-init-list;
otherwise, an iterating expansion statement if its expansion-initializer is an expansion-iterable expression;
otherwise, a destructuring expansion statement.
An expansion statement S is equivalent to a compound-statement containing instantiations of the for-range-declaration (including its implied initialization), together with the compound-statement of S, as follows:
If S is an enumerating expansion statement, S is equivalent to:{init-statementS0 ⋮ SNâ1} where N is the number of elements in the expression-list,Si is{for-range-declaration = Ei; compound-statement} and Ei is the ith element of the expression-list.
Otherwise, if S is an iterating expansion statement, S is equivalent to:{init-statementstatic constexpr auto&& range = expansion-initializer; static constexpr auto begin = begin-expr; // see [stmt.ranged]static constexpr auto end = end-expr; // see [stmt.ranged]S0 ⋮ SNâ1} where N is the result of evaluating the expression[] consteval { std::ptrdiff_t result = 0; for (auto i = begin; i != end; ++i, ++result); return result; // distance from begin to end}() and Si is{static constexpr auto iter = begin + i; for-range-declaration = *iter; compound-statement} The variables range, begin, end, and iter are defined for exposition only. [Note 1: The instantiation is ill-formed if range is not a constant expression ([expr.const]). â end note]
Otherwise, S is a destructuring expansion statement and S is equivalent to:{init-statementconstexpropt auto&& [u0, u1, …, uNâ1] = expansion-initializer; S0 ⋮ SNâ1} where N is the structured binding size of the type of the expansion-initializer and Si is{for-range-declaration = ui; compound-statement} The keyword constexpr is present in the declaration of u0,u1,â¦,uNâ1 if and only ifconstexpr is one of the decl-specifiers of the decl-specifier-seq of the for-range-declaration.
[Example 1: consteval int f(auto const&... Containers) {int result = 0; template for (auto const& c : {Containers...}) { // OK, enumerating expansion statement result += c[0]; }return result;}constexpr int c1[] = {1, 2, 3};constexpr int c2[] = {4, 3, 2, 1};static_assert(f(c1, c2) == 5); â end example]
[Example 2: consteval int f() {constexpr std::array<int, 3> arr {1, 2, 3}; int result = 0; template for (constexpr int s : arr) { // OK, iterating expansion statement result += sizeof(char[s]); }return result;}static_assert(f() == 6); â end example]
[Example 3: struct S {int i; short s;};
consteval long f(S s) {long result = 0; template for (auto x : s) { // OK, destructuring expansion statement result += sizeof(x); }return result;}static_assert(f(S{}) == sizeof(int) + sizeof(short)); â end example]