可变参数模版中的折叠表达式

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(args),这为每个参数创建一个AddSpace 对象,该对象引用传递的参数,并在输出表达式时使用该参数添加一个空格。

posted @ 2025-12-07 20:17  jigsawecho  阅读(2)  评论(0)    收藏  举报