Fold expressions

来源:互联网 发布:python能开发界面吗 编辑:程序博客网 时间:2024/06/01 18:26

Fold expressions

With C++11 we got variadic templates which is a great feature, especially if you want to work with a variable number of input parameters to a function. For example, previously (pre C++11) you had to write several different versions of a function (like one for one parameter, another for two parameters, another for three params… ).

Still, variadic templates required some additional code when you wanted to implement ‘recursive’ functions like sum, all. You had to specify rules for the recursion:

For example:

auto SumCpp11(){    return 0;}template<typename T1, typename... T>auto SumCpp11(T1 s, T... ts){    return s + SumCpp11(ts...);}

And with C++17 we can write much simpler code:

template<typename ...Args> auto sum(Args ...args) {     return (args + ... + 0); }// or even:template<typename ...Args> auto sum2(Args ...args) {     return (args + ...);}

Simple folds

#include <iostream>#include <string>using namespace std;template<typename ...Args> auto sum(Args ...args) {     return (args + ... + 0); }template<typename ...Args> auto sum2(Args ...args) {     return (args + ...);}int main(){    cout << sum(1, 2, 3, 4, 5, 6, 7) << "\n";    cout << sum2(1, 2, 3, 4, 5, 6, 7) << "\n";}

Run
Fold expressions over a parameter pack.

EXPRESSION EXPANSION
(… op pack) ((pack1 op pack2) op …) op packN
(init op … op pack) (((init op pack1) op pack2) op …) op packN
(pack op …) pack1 op (… op (packN-1 op packN))
(pack op … op init) pack1 op (… op (packN-1 op (packN op init)))

Also by default we get the following values for empty parameter packs:

OPERATOR DEFAULT VALUE
&& true
|| false
, void()
Here’s quite nice implementation of a printf using folds P0036R0:

template<typename ...Args>void FoldPrint(Args&&... args) {    (cout << ... << forward<Args>(args)) << '\n';}

Print and folds

#include <iostream>#include <string>using namespace std;template<typename ...Args>void FoldPrint(Args&&... args) {    (cout <<  ... <<  forward<Args>(args)) << '\n';}int main(){    FoldPrint("hello", ", ", 10, ", ", 90.0);}
Success!Standard Outputhello, 10, 90

Or a fold over a comma operator:

template<typename T, typename... Args>void push_back_vec(std::vector<T>& v, Args&&... args){    (v.push_back(args), ...);}

Push back and folds

#include <iostream>#include <string>#include <vector>using namespace std;template<typename T, typename... Args>void FoldPushBack(vector<T>& v, Args&&... args){    (v.push_back(args), ...);}int main(){    vector<int> v;    FoldPushBack(v, 1, 2, 3, 4);    for (auto &i : v)        cout << i << "\n";}

Run
In general, fold expression allows writing cleaner, shorter and probably easier to read code.

More details in:

  • N4295 and P0036R0 “Using fold expressions to simplify variadic
    function templates” in Modern C++ Programming Cookbook.
  • Simon Brand: Exploding tuples with fold expressions
  • Baptiste Wicht: C++17 Fold Expressions
  • Fold Expressions - ModernesCpp.com
  • MSVC not yet, GCC: 6.0, Clang: 3.6 (N4295)/3.9(P0036R0).
原创粉丝点击