编写一个通用遍历函数,允许灵活地处理具有不同参数的多个函数

Writing a generic traverse function that allows the flexibility of dealing with multiple functions with differing parameters

本文关键字:函数 处理 参数 许灵活 一个 遍历      更新时间:2023-10-16

我想使用 std::function 来帮助我运行一个遍历 BST 并调用参数化函数的通用遍历函数。

我的困难在于参数化函数在其自身的参数中变化。

因此,例如,我要概括以下三个函数(它们的参数都不同(。

//populates an array with the values in the BST by traversing the BST
void LinkedBST<T>::populate(T const * const data, size_t & I, Node *x)
{
      data[i++] = x->val;
}
//insert unique values of another BST into "this" BST: traverses the other BST and inserts every value
void LinkedBST<T>::insert(Node *x)
{
      insert(x->val);
}

与其为上述每个函数编写单独的遍历函数,我希望能够将它们传递到一个通用遍历函数中,如下所示:

void LinkedBST<T>::traverse(Node *x, auto func)
{
     if(x == nullptr)
          return;
     traverse(x->left, func);
     func( <parameters> );
     traverse(x->right, func);
}

有什么办法可以做到这一点吗?如果有,你能帮我做吗?

谢谢:)

通常,您需要找到一种方法来标准化所有遍历回调的签名。一种选择是使用 lambda 并利用 lambda 捕获来减少函数的参数数量。

void LinkedBST<T>::populate(T const * const data, size_t & I)
{
    traverse(root, [&](Node * x) {
            data[i++] = x->val;
        });
}

请注意,同一遍历函数不能用于compare因为您需要同时遍历两棵树。目前还不清楚insert应该做什么,但从评论中听起来也需要同时遍历。

一种解决方案是模板化遍历函数以采用函数对象。 然后,不要在 traverse 函数中指定参数,而是将这些参数移动到函数对象,并让函数对象的operator()在调用时处理详细信息:

template <typename func>
void LinkedBST<T>::traverse(Node *x, func fn)
{
     if(x == nullptr)
          return;
     traverse(x->left, fn);
     fn(x->val);
     traverse(x->right, fn);
}
struct some_func
{
   int param1;
   int param2;
   int param3;
   some_func(int p1, int p2, int p3) : param1(p1), param2(p2), param3(p3) {}
   void operator()(int node_value) 
   {
      std::cout << "The node value is " << node_value << "n";
      // the parameters are param1, param2, param3
   }
};

调用 operator()(调用函数(时,您现在拥有节点值以及您在对象内设置的所有参数。

然后可以做这样的事情:

Node *node_ptr;
//...
LinkedBST<int> the_list;
//...
some_func f(1,2,3);  // we want to use 1,2,3 as the parameters to the custom function
the_list.traverse(node_ptr, f);

下面是使用虚拟类显示基础知识的简化版本。


您也可以通过以下技术使用 lambda:

Node *node_ptr;
//...
LinkedBST<int> the_list;
//...
int arg1=1, arg2=2, arg3=3;
the_list.traverse(node_ptr, 
                  [&](int node_value){std::cout << "The node value is " << 
                                      node_value << "n" << arg1 << " " << 
                                      arg2 << " " << arg3;});