• C++17折叠表达式(Fold Expressions)


    语法

    template
    
    • 1
    1. ( args op ... )(一元右折叠)
    2. ( ... op args)(一元左折叠)
    3. ( args op ... op init )(二元右折叠)
    4. ( init op ... op args)(二元左折叠)

    说明

    • op - 下列 32 个二元操作符之一:+ - * / % ^ & | = < > << >> += -= *= /= %= ^= &= |= <<= >>= == != <= >= && || , .* ->*。在二元折叠中,两个 op 必须相同。
    • pack - 包含未展开的参数包的表达式
    • init - 不包含未展开的参数包的表达式
    • 注意,括号是折叠表达式的必要组成部分。

    注意

    如果作为 initpack 的表达式包含最高级别低于 cast 的优先级的操作符,则必须将其括在括号内:

    template<typename... Args>
    int sum(Args&&... args)
    {
    //  return (args + ... + 1 * 2);   // 错误:*操作符优先级低于 cast
        return (args + ... + (1 * 2)); // 正确
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解释

    对折叠表达式的实例化会按照以下方式展开表达式 e

    1. 一元右折叠 (E op ...) 变成 (E op (... op (EN-1 op EN)))
    2. 一元左折叠 (... op E) 变成 (((E1 op E2) op ...) op EN)
    3. 二元右折叠 (E op ... op I) 变成 (E1 op (... op (EN−1 op (EN op I))))
    4. 二元左折叠 (I op ... op E) 变成 ((((I op E1) op E2) op ...) op EN)(其中 N 是参数包扩展中的元素数)

    例如,

    template<typename... Args>
    bool all(Args... args) { return (... && args); }
     
    bool b = all(true, true, true, false);
    // 在 all() 中,一元左折叠展开为
    //  return ((true && true) && true) && false;
    // b 为 false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    综合示例

    记住Args是模板参数包,展开后是每个参数类型,args是函数参数包,展开后是一个个的参数变量

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    template<typename... Args>
    void printer(Args&&... args)
    {
        (std::cout << ... << args) << '\n';
        // 展开后:std::cout << arg1 << arg2 << ... << argN
    }
     
    template<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)), ...);
        // 两个折叠表达式,展开后相当于
        // std::is_constructible_v && std::is_constructible_v && ... && std::is_constructible_v
        // v.push_back(std::forward(arg1)), v.push_back(std::forward(arg2)), ..., v.push_back(std::forward(argN))
    }
    
    // 这个函数的目的是将输入的整数 `i` 进行字节交换,并返回结果
    template<class T, std::size_t... dummy_pack>
    constexpr T bswap_impl(T i, std::index_sequence<dummy_pack...>)
    {
        T low_byte_mask = (unsigned char)-1;
        T ret{};
        ([&]
        {
            (void)dummy_pack;
            ret <<= CHAR_BIT;
            ret |= i & low_byte_mask;
            i >>= CHAR_BIT;
        }(), ...);
    	// ([&] { ... }(), [&] { ... }(), ...)
        return ret;
    }
    
     
    int main()
    {
        printer(1, 2, 3, "abc");
     
        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';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    输出:

    123abc
    6 2 45 12 1 2 9
    
    • 1
    • 2
  • 相关阅读:
    解析数仓lazyagg查询重写优化
    java 代码块(静态代码块、局部代码块、构造代码块)
    2021年PHP-Laravel面试题问卷题 答案记录
    visual studio code中base环境切换的问题
    熊市链游模型如何设计开发?
    招投标系统软件源码,招投标全流程在线化管理
    2022年面试复盘大全400道:Redis+ZK+Nginx+数据库+分布式+微服务
    前端打工人的面试总结
    d为何用nan作为浮点默认
    [HTML/CSS基础]知识点汇总
  • 原文地址:https://blog.csdn.net/Motarookie/article/details/134511603