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))
上一篇:C# .NET实现变量自身名字


下一篇:CSCI3136 Assignment