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

淺唱寂寞╮ 提交于 2020-01-03 03:25:06

问题


I want to employ std::function to help me run a generic traverse function that traverses a BST and calls the parametrized function.

My difficulty is that the parametrized function varies in its own parameters.

So, for example, I was to generalize the following three functions (all different in their parameters).

//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);
}

Instead of writing a separate traverse function for each one of the aforementioned functions, I want to be able to pass them into one generic traverse function, something like:

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

     traverse(x->left, func);
     func( <parameters> );
     traverse(x->right, func);
}

Is there any way to do this? If there is, can you help me do it?

Thank you :)


回答1:


One solution is to templatize your traverse function to take a function object. Then instead of specifying the parameters in the traverse function, move those parameters to the function object and let the function object's operator() handle the details when called:

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
   }
};

When the operator() is invoked (the function is called), you now have the node value, plus all the parameters you set inside the object.

Then something like this can be done:

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);

Here is a simplified version showing the basics by using a dummy class.


You could also use a lambda with this technique:

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;});



回答2:


In general, you will need to find a way to standardise the signature to all of your traversal callbacks. One option is to use lambdas and make use of lambda captures to reduce the number of arguments to your functions.

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

Note that the same traversal function couldn't be used for compare because you need to simultaneously traverse two trees. And it's not clear what insert is even supposed to be doing, but from the comment it sounds like it would require a simultaneous traversal as well.



来源:https://stackoverflow.com/questions/55930796/writing-a-generic-traverse-function-that-allows-the-flexibility-of-dealing-with

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!