我想使用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);
}
有没有办法做到这一点?如果有,您能帮我吗?
谢谢:)
答案 0 :(得分:2)
通常,您将需要找到一种方法来标准化所有遍历回调的签名。一种选择是使用lambda,并使用lambda捕获来减少函数参数的数量。
void LinkedBST<T>::populate(T const * const data, size_t & I)
{
traverse(root, [&](Node * x) {
data[i++] = x->val;
});
}
请注意,compare
不能使用相同的遍历函数,因为您需要同时遍历两棵树。还不清楚insert
应该做什么,但是从注释看来,它也需要同时遍历。
答案 1 :(得分:1)
一种解决方案是对遍历函数进行模板化以获取一个函数对象。然后,无需在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);
这里是simplified version,显示了通过使用虚拟类的基础知识。
您还可以通过此技术使用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;});