C++17对可变长模板参数引入了折叠表达式,以简化对参数包的处理,也可以避免递归调用。
C++17前如果想实现一个可变长参数相加,需要这样实现:
- #include <iostream>
- using namespace std;
-
- template<class T>
- auto add(T t)
- {
- return t;
- }
-
- template<class T, class ...Args>
- auto add(T t, Args... args)
- {
- return t + add(args...); //通过递归调用实现
- }
-
- int main()
- {
- cout<<add(1)<<endl; //输出:1
- cout<<add(1, 2)<<endl; //输出:3
- cout<<add(1, 2, 3)<<endl; //输出:6
- cout<<add(1, 2, 3, 4)<<endl; //输出:10
- return 0;
- }
C++17的折叠表达式可以简化实现的方式:
- #include <iostream>
- using namespace std;
-
- template <class ... Ts>
- auto add(Ts ... ts)
- {
- return (... + ts); //折叠表达式
- }
-
- int main()
- {
- cout<<add(1)<<endl; //输出:1
- cout<<add(1, 2)<<endl; //输出:3
- cout<<add(1, 2, 3)<<endl; //输出:6
- cout<<add(1, 2, 3, 4)<<endl; //输出:10
- return 0;
- }
折叠表达式支持 32 个操作符:
+ | - | * | / | % | ^ | & |
| | = | < | > | << | >> | += |
-= | *= | /= | %= | ^= | &= | |= |
<<= | >>= | == | != | <= | >= | && |
|| | .* | ->* | , |
折叠表达式共有四种语法形式。分别为一元的左折叠和右折叠,以及二元的左折叠和右折叠。
1.一元右折叠(unary right fold)
( pack op ... )
一元右折叠(E op ...)展开之后变为 E1 op (... op (EN-1 op EN))
2.一元左折叠(unary left fold)
( ... op pack )
一元左折叠(... op E)展开之后变为 ((E1 op E2) op ...) op EN
3.二元右折叠(binary right fold)
( pack op ... op init )
二元右折叠(E op ... op I)展开之后变为 E1 op (... op (EN−1 op (EN op I)))
4.二元左折叠(binary left fold)
( init op ... op pack )
二元左折叠(I op ... op E)展开之后变为 (((I op E1) op E2) op ...) op EN
注:
1.语法形式中的op代表运算符,pack代表参数包,init代表初始值。
2.初始值在右边的为右折叠,展开之后从右边开始折叠。而初始值在左边的为左折叠,展开之后从左边开始折叠。
3.不指定初始值的为一元折叠表达式,而指定初始值的为二元折叠表达式。
4.当一元折叠表达式中的参数包为空时,只有三个运算符(&& || 以及逗号)有缺省值,其中&&的缺省值为true,||的缺省值为false,逗号的缺省值为void()。