浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第4章 可变参数模板:4.2 折叠表达式

Posted on 2020-04-18 18:04  浅墨浓香  阅读(917)  评论(0编辑  收藏  举报

4.2 Fold Expressions

4.2 折叠表达式

 

Since C++17, there is a feature to compute the result of using a binary operator over all the arguments of a parameter pack (with an optional initial value).

从C++17开始,有一个特性可以使用二元运算符对参数包中的所有参数进行计算,以获取结果(参数包可带有可选的初始值)。

For example, the following function returns the sum of all passed arguments:

例如,下面的函数返回所有传入的实参之和:

template<typename… T>
auto foldSum (T… s) {
    return (… + s); // ((s1 + s2) + s3) …
}

If the parameter pack is empty, the expression is usually ill-formed (with the exception that for operator && the value is true, for operator || the value is false, and for the comma operator the value for an empty parameter pack is void()).

如果是空参数包,则表达式通常是格式错误的(例外:如果使用运算符&&,则值为true。如果使用运算符||,则值为false。如果使用逗号运算符,则值为void())。

 

Table 4.1 lists the possible fold expressions.

表格4.1列出了所有可能的折叠表达式。

 

You can use almost all binary operators for fold expressions (see Section 12.4.6 on page 208 for details). For example, you can use a fold expression to traverse a path in a binary tree using operator ->*:

几乎所有的二元运算符都可以用于折叠表达式(有关详细信息,请参阅第208页的12.4.6节)。例如,可以使用折叠表达式通过“->*”运算符沿一条路径遍历二叉树。

// 定义二叉树结构体和遍历辅助函数:
struct Node {
    int value;
    Node* left;
    Node* right;
    Node(int i = 0) : value(i), left(nullptr), right(nullptr) {}
    ...
};

//成员指针
auto left = &Node::left;   //等价于Node* Node::*left = &Node::left;
auto right = &Node::right; //等价于Node* Node::*right = &Node::right;

// 使用折叠表达式按指定路径(paths)来遍历二叉树:
template<typename T, typename... TP>
Node* traverse(T np, TP... paths) {
    return (np->*…->*paths); // np ->* paths1 ->* paths2 …
}

int main()
{
    //初始化二叉树结构体:
    Node* root = new Node{ 0 };
    root->left = new Node{ 1 };
    root->left->right = new Node{ 2 };

    ...

        //遍历二叉树 :
        Node* node = traverse(root, left, right); //从根节点开始,沿着向左再向右的路径找出
                                                  //相应的节点(即,value为2的节点)
    ...
}

Here, (np ->* … ->* paths) uses a fold expression to traverse the variadic elements of paths from np.

此外,(np->*…->*paths)利用折叠表达式从np节点开始,遍历了路径上数量不定的元素。

 

With such a fold expression using an initializer, we might think about simplifying the variadic template to print all arguments, introduced above:

对于使用初始化器那样的一个折叠表达式,我们可能会考虑简化可变参数模板来打印上面介绍的所有参数。

template<typename… Types>
void print (Types const&… args)
{
    (std::cout << … << args) << ‘\n’;
}

However, note that in this case no whitespace separates all the elements from the parameter pack. To do that, you need an additional class template, which ensures that any output of any argument is extended by a space:

但是,要注意,在这种情况下,没有用空格分隔参数包中的元素。为了做到这点,你需要一个额外的类模板,它可以确保任何参数的输出都用空格扩展。

template<typename T>
class AddSpace
{
private:
    T const& ref; //指向从构造函数中传递进来的参数
public:
    AddSpace(T const& r) : ref(r) {
    }

    friend std::ostream& operator<< (std::ostream& os, AddSpace<T> s) {
        return os << s.ref << ' '; // 输出传递进来的参数和一个空格
    }
};

template<typename... Args>
void print(Args... args) {
    (std::cout << ... << AddSpace(args)) << '\n';
}

Note that the expression AddSpace(args) uses class template argument deduction (see Section 2.9 on page 40) to have the effect of AddSpace<Args> (args), which for each argument creates an AddSpace object that refers to the passed argument and adds a space when it is used in output expressions.

注意, AddSpace(args)表达式使用了类模板参数推导(请参阅第40页的2.9节)来产生AddSpace<Args>(args)的效果。它为每个参数创建一个指向该参数的AddSpace对象,在输出表达式中使用该对象时会添加一个空格。

See Section 12.4.6 on page 207 for details about fold expressions.

关于折叠表达式更多的细节,请参阅第207页的12.4.6节。