zoukankan      html  css  js  c++  java
  • C++17 Fold Expressions

    C++17 Fold Expressions

    本文介绍C++17新特性折叠表达式。文章示例代码通过MinGW编译,宏__cplusplus=201703

    下面我们从一个模板函数sum开始,介绍折叠表达式。

    用折叠表达式简化以前的代码

    C++11引入了变长参数模板,我们想求变长参数的和,可以这样写模板函数

    template <typename T>
    auto sum(T arg){
        return arg;
    }
    
    template <typename T1, typename... T>
    auto sum(T1 arg, T... args){
        return arg + sum(args...);
    }
    
    int main() {
        std::cout<<sum(1,2,3)<<std::endl;
        return 0;
    }
    

    注:这里用到了auto推导,C++14编译没问题。用C++11编译的读者记得在函数签名后面加"-> T"

    为了完成sum这个函数,我们需要写2个函数。一个进行递归,一个作为递归返回条件。这种模板的递归是在编译时发生的,遇到复杂的递归会大大加大编译时间。有没有办法写一个模板函数,同时又能实现sum功能呢?

    有,就是折叠表达式

    我们看下折叠表达式的写法

    template <typename... T>
    auto sum_folder(T... args) {
        return (... + args);
    }
    
    int main() {
        std::cout<<sum_folder(1,2,3)<<std::endl;
        return 0;
    }
    

    这里折叠表达式会将sum_folder(1,2,3)扩展成(1+(2+3))

    如何使用折叠表达式

    看了上面的例子,相信读者对折叠表达式已经有了直观的认识。下面我们详细介绍下折叠表达式的使用。

    一元折叠

    假设参数是args,操作符是op。一元折叠有两种情况:左折叠和右折叠

    1. unary left fold: (... op args) expends to ((arg1 op arg2) op arg3) + ...
    2. unary right fold: (args op ...) expends to arg1 op (arg2 op ... (argN-1 op argN))

    举2个例子方便理解

    左折叠

    template<typename... T>
    string combine_str_left(T... args) {
        return (... + args);
    }
    
    string s("head");
    // expand to (s+" ") + "tail"
    std::cout<<combine_str_left(s," ","tail")<<std::endl;
    

    右折叠

    template<typename... T>
    string combine_str_right(T... args) {
        return (args + ...);
    }
    

    右折叠就不能combine_str_right(s," ", "tail")这么写,因为扩展开来是s + (" " + "tail")显然两个字面值是不能直接相加的。所以比起右折叠,左折叠用的比较多。

    二元折叠

    1. binary left fold: (value op ... op args) expand to ((value op arg1) op arg2) op ...
    2. binary right fold: (args op ... op value) expand to args1 op (arg2 op ... ( argN op value))

    同样举个左折叠的例子

    template<typename... T>
    void print(const T&... args) {
        (std::cout << ... << args);
    }
    
    print("a","b", "c"); // print abc
    

    想让各个参数中间打印一个空格,可以使用一个lambda处理下

    template<typename First, typename... T>
    void print(const First& first,const T&... args) {
        std::cout<<first;
        auto whiteSpaceWrapper = [](const auto& arg){
            std::cout<<" ";
            return arg;
        };
        (std::cout << ... << whiteSpaceWrapper(args));
    }
    

    lambda表达式使用fold expressions

    折叠表达式不仅用于模板,也可以用在lambda表达式里面

    auto print = [](auto&... args){ (std::cout << args << ... ) << '
    ';};
    print("first", "second", "third");
    
  • 相关阅读:
    数值微分(数学)(组合数)
    破冰派对(搜索)
    [NOIP2017]宝藏
    [NOIP2013]华容道
    收集邮票(数学期望)
    序列(DP)(组合数)
    luogu1357花园(矩阵运算)(状压DP)
    游戏(期望)
    [NOIP2012]疫情控制
    [NOIP2012] 开车旅行
  • 原文地址:https://www.cnblogs.com/pusidun/p/13608761.html
Copyright © 2011-2022 走看看