Folding expressions

Andrew Sutton, Richard Smith
Date: 2014-11-07
Document number: N4295
Revises: N4191

Wording

5.1. Primary expressions [expr.prim]

Modify the grammar of primary-expression in [expr.prim] to include fold expressions.

primary-expression:
fold-expression

Add the a new subsection to [expr.prim] called "Fold expressions".

5.1.3 Fold expressions [expr.prim.fold]

A fold expression performs a fold of a template parameter pack ([temp.variadic]) over a binary operator.

fold-expression:
( cast-expression fold-operator ... )
( ... fold-operator cast-expression )
( cast-expression fold-operator ... fold-operator cast-expression )

fold-operator: one of
+  -  *  /  %  ^  &  |  ~  =  <  >  <<  >>
+=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=
==  !=  <=  >=  &&  ||  ,  .*  ->*

An expression of the form (... op e) where op is a fold-operator is called a unary left fold. An expression of the form (e op ...) where op is a fold-operator is called a unary right fold. Unary left folds and unary right folds are collectively called unary folds. In a unary fold, the cast-expression shall contain an unexpanded parameter pack.

An expression of the form (e1 op1 ... op2 e2) where op1 and op2 are fold-operators is called a binary fold. In a binary fold, op1 and op2 shall be the same fold-operator, and either e1 shall contain an unexpanded parameter pack or e2 shall contain an unexpanded parameter pack, but not both. If e2 contains an unexpanded parameter pack, the expression is called a binary left fold. If e1 contains an unexpanded parameter pack, the expression is called a binary right fold. [ Example:

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 parameter packs
}

end example]

Add a new bullet to paragraph 4:

• In a fold-expression (5.1.3); the pattern is the cast-expression that contains an unexpanded parameter pack.

Change in paragraph 7:

The instantiation of a pack expansion that is notneither a sizeof... expression nor a fold-expression produces a list E1, E2, ..., EN [...]

Add a new paragraph after paragraph 8:

The instantiation of a fold-expression produces:

• ((E1 op E2) op ...) op EN for a unary left fold,
• E1 op (... op (EN-1 op EN)) for a unary right fold,
• (((E op E1) op E2) op ...) op EN for a binary left fold, and
• E1 op (... op (EN-1 op (EN op E))) for a binary right fold.

In each case, op is the fold-operator, N is the number of elements in the pack expansion parameters, and each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. For a binary fold-expression, E is generated by instantiating the cast-expression that did not contain an unexpanded parameter pack. [ Example:

template<typename... Args>
bool all(Args... args) { return (args && ...); }

bool b = all(true, true, true, false);

Within the instantiation of all, the returned expression expands to ((true && true) && true) && false, which evalutes to false. — end example ] If N is zero for a unary fold-expression, the value of the expression is shown in Table N; if the operator is not listed in Table N, the instantiation is ill-formed.

Table N. Value of folding empty sequences
Operator Value when parameter pack is empty
* 1
+ int()
& -1
| int()
&& true
|| false
, void()

14.6.2.2 Type-dependent expressions [temp.dep.expr]

Add a new paragraph after paragraph 6:

A fold-expression is type-dependent.

14.6.2.3 Value-dependent expressions [temp.dep.constexpr]

Change in paragraph 4:

Expressions of the following form are value-dependent:

sizeof...( identifier )

fold-expression