| General topics | ||||||||||||||||
| Flow control | ||||||||||||||||
| Conditional execution statements | ||||||||||||||||
| Iteration statements (loops) | ||||||||||||||||
| Jump statements | ||||||||||||||||
| Functions | ||||||||||||||||
| Function declaration | ||||||||||||||||
| Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
| Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
| Exceptions | ||||||||||||||||
| Namespaces | ||||||||||||||||
| Types | ||||||||||||||||
| Specifiers | ||||||||||||||||
| ||||||||||||||||
| Storage duration specifiers | ||||||||||||||||
| Initialization | ||||||||||||||||
| Expressions | ||||||||||||||||
| Alternative representations | ||||||||||||||||
| Literals | ||||||||||||||||
| Boolean -Integer -Floating-point | ||||||||||||||||
| Character -String -nullptr(C++11) | ||||||||||||||||
| User-defined(C++11) | ||||||||||||||||
| Utilities | ||||||||||||||||
| Attributes(C++11) | ||||||||||||||||
| Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
| Type alias declaration(C++11) | ||||||||||||||||
| Casts | ||||||||||||||||
| Memory allocation | ||||||||||||||||
| Classes | ||||||||||||||||
| Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
| Special member functions | ||||||||||||||||
| Templates | ||||||||||||||||
| Miscellaneous | ||||||||||||||||
| General | |||||||||||||||||||||||||||||||||||||||||||||||||||
| Literals | |||||||||||||||||||||||||||||||||||||||||||||||||||
| Operators | |||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||
| Conversions | |||||||||||||||||||||||||||||||||||||||||||||||||||
Reduces (folds) apack over a binary operator.
Contents |
(pack op... ) | (1) | ||||||||
( ...op pack) | (2) | ||||||||
(pack op...op init) | (3) | ||||||||
(init op...op pack) | (4) | ||||||||
| op | - | any of the following 32binary operators:+-*/%^&|=<><<>>+=-=*=/=%=^=&=|=<<=>>===!=<=>=&&||,.*->*. In a binary fold, bothops must be the same. |
| pack | - | an expression that contains an unexpandedpack and does not contain an operator withprecedence lower than cast at the top level (formally, acast-expression) |
| init | - | an expression that does not contain an unexpandedpack and does not contain an operator withprecedence lower than cast at the top level (formally, acast-expression) |
Note that the opening and closing parentheses are a required part of the fold expression.
The instantiation of afold expression expands the expressione as follows:
(Eop...) becomes(E1op(...op(EN-1opEN)))(...opE) becomes(((E1opE2)op ...)opEN)(Eop...opI) becomes(E1op(...op(EN−1op(ENopI))))(Iop...opE) becomes((((IopE1)opE2)op ...)opEN)(whereN is the number of elements in the pack expansion)
For example,
template<typename...Args>bool all(Args...args){return(...&& args);} bool b= all(true,true,true,false);// within all(), the unary left fold expands as// return ((true && true) && true) && false;// b is false
When a unary fold is used with a pack expansion of length zero, only the following operators are allowed:
If the expression used asinit or aspack has an operator withprecedence below cast at the top level, it must be parenthesized:
template<typename...Args>int sum(Args&&...args){// return (args + ... + 1 * 2); // Error: operator with precedence below castreturn(args+ ...+(1*2));// OK}
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_fold_expressions | 201603L | (C++17) | Fold expressions |
#include <climits>#include <concepts>#include <cstdint>#include <iostream>#include <limits>#include <type_traits>#include <utility>#include <vector> // Basic usage, folding variadic arguments over operator<<template<typename...Args>void printer(Args&&...args){(std::cout<< ...<< args)<<'\n';} // Folding an expression that uses the pack directly over operator,template<typename...Ts>void print_limits(){((std::cout<<+std::numeric_limits<Ts>::max()<<' '), ...)<<'\n';} // Both a fold over operator&& using the pack// and over operator, using the variadic argumentstemplate<typename T,typename...Args>void push_back_vec(std::vector<T>& v, Args&&...args){ static_assert((std::is_constructible_v<T, Args&&>&& ...));(v.push_back(std::forward<Args>(args)), ...);} // Using an integer sequence to execute an expression// N times by folding a lambda over operator,template<class T,std::size_t...dummy_pack>constexpr T bswap_impl(T i,std::index_sequence<dummy_pack...>){ T low_byte_mask=static_cast<unsignedchar>(-1); T ret{};([&]{(void)dummy_pack; ret<<=CHAR_BIT; ret|= i& low_byte_mask; i>>=CHAR_BIT;}(), ...);return ret;} constexprauto bswap(std::unsigned_integralauto i){return bswap_impl(i,std::make_index_sequence<sizeof(i)>{});} int main(){ printer(1,2,3,"abc"); print_limits<uint8_t, uint16_t, uint32_t>(); std::vector<int> v; push_back_vec(v,6,2,45,12); push_back_vec(v,1,2,9);for(int i: v)std::cout<< i<<' ';std::cout<<'\n'; static_assert(bswap<std::uint16_t>(0x1234u)== 0x3412u); static_assert(bswap<std::uint64_t>(0x0123456789abcdefull)== 0xefcdab8967452301ULL);}
Output:
123abc255 65535 4294967295 6 2 45 12 1 2 9
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| CWG 2611 | C++17 | the expansion results of fold expressions were not enclosed with parentheses | enclosed with parentheses |