可变参数模版中的折叠表达式
C++17 后,有一个特性可以对参数包的所有参数使用二元运算符计算结果(初始值可选)。
例如,下面的函数会返回所有入参的和:
template<typename... T>
auto foldSum (T... s)
{
return (... + s); // ((s1 + s2) + s3) ...
}
若参数包为空,表达式通常是错误格式的(除了操作符&& 的值为true,操作符|| 的值为false,逗号操作符空参数包的值为void())。
下表列出了可能的折叠表达式。
| 折叠表达式 | 展开 |
|---|---|
| ( ... op pack ) | ((( pack1 op pack2 ) op pack3 ) ... op packN ) |
| ( pack op ... ) | ( pack1 op ( ... ( packN-1 op packN ))) |
| ( init op ... op pack ) | ((( init op pack1 ) op pack2 ) ... op packN ) |
| ( pack op ... op init ) | ( pack1 op ( ... ( packN op init ))) |
几乎所有的二元运算符都可以使用折叠表达式。例如,可以使用折叠表达式来遍历一个二叉树的路径,使用操作符->*:
foldtraverse.cpp
// define binary tree structure and traverse helpers:
struct Node
{
int value;
Node* left;
Node* right;
Node(int i=0) : value(i), left(nullptr), right(nullptr)
{
}
...
};
auto left = &Node::left;
auto right = &Node::right;
// traverse tree, using fold expression:
template<typename T, typename... TP>
Node* traverse (T np, TP... paths)
{
return (np ->* ... ->* paths); // np ->* paths1 ->* paths2 ...
}
int main()
{
// init binary tree structure:
Node* root = new Node{0};
root->left = new Node{1};
root->left->right = new Node{2};
...
// traverse binary tree:
Node* node = traverse(root, left, right);
...
}
这里,
(np ->* ... ->* paths)
使用折叠表达式遍历从 np 开始的可变元素路径。
这种使用初始化器的折叠表达式,可以简化可变参数模板来打印上面的所有参数:
template<typename... Types>
void print (Types const&... args)
{
(std::cout << ... << args) << '\n';
}
但无法为参数包中的每个元素输出添加打印空格。要添加空格,需要一个额外的类模板,确保参数的输出都会添加一个空格:
addspace.hpp
template<typename T>
class AddSpace
{
private:
T const& ref; // refer to argument passed in constructor
public:
AddSpace(T const& r): ref(r)
{
}
friend std::ostream& operator<< (std::ostream& os, AddSpace<T> s)
{
return os << s.ref << ' '; // output passed argument and a space
}
};
template<typename... Args>
void print (Args... args)
{
( std::cout << ... << AddSpace(args) ) << '\n';
}
表达式AddSpace(args) 使用类模板参数推断产生AddSpace

浙公网安备 33010602011771号