522 字
3 分钟
14模板折叠
2025-02-18

模板折叠#

模板折叠用于在模板中,将可变长度参数,向左或者向右展开,并进行运算

  • 左折叠: (init op ... op args) or ... op args
  • 右折叠: (args op ... op init) or args op ...

其中,args表示输入的参数;op为运算符(操作符),对args进行运算;...表示占位符,表示折叠后的内容。

模板折叠代码需要先展开,再根据展开的结果运算

例子:

// 展开为表达式
(... + args);
-> (((arg1 + arg2) + arg3) + arg4);
-> (arg1 + arg2 + arg3 + arg4);
// 展开为函数参数列表
(std::max)(first, ..., args);
-> (std::max)((((first, arg1), arg2), arg3), arg4)
-> (std::max)(first, arg1, arg2, arg3, arg4);

由于我们的代码一般都是从左往右执行,因此左折叠使用的较多

但是当需要从右往左执行的情况时(如,字符串从右往左),需要使用到右折叠。

甚至左折叠和右折叠混合使用。

展开#

左折叠的展开(... op args)后,从左向右运行

(((arg1 op arg2) op arg3) op arg4)
// 如果是init op ... op args,展开结果为
((((init op arg1) op arg2) op arg3) op arg4)

右折叠展开args... op后,从右向左运行

(arg1 op (arg2 op (arg3 op arg4)))
// 如果是args op ... op init,展开结果为
(arg4 op (arg3 op (arg2 op (arg1 op init))))

根据左右折叠的执行方向不同,因此需要根据运算符的结合顺序选择合适的折叠方式

例如:如果op<<运算符,因为<<运算符是左结合的,使用右折叠会存在一些问题,在visual studio中无法通过编译。

#include <iostream>
template<typename ... Args>
auto printLeftStr(const Args& ... args) -> decltype(auto) {
return (std::cout << ... << args);
}
/*
错误,args无法与<<结合
*/
//template<typename ... Args>
//auto printRightStr(const Args& ... args) -> decltype(auto) {
// return (args << ... << std::cout);
//}
int main() {
printLeftStr("1", "2", "Hello", "World", "!", "3");
//printRightStr("1", "2", "Hello", "World", "!", "3");
}

上述代码中,

(args << ... << std::cout); 展开后为:

(arg1 << (arg2 << (arg3 << (arg4 << std::cout))))

因为<<为左结合,展开后优先和arg4结合,由于arg4不一定是ostream类型,因此会报错。

14模板折叠
https://chrisnake11.github.io/blog/posts/coding/c基础/14模板折叠/
作者
Zheyv
发布于
2025-02-18
许可协议
CC BY-NC-SA 4.0