Написание универсальной функции перемещения, которая позволяет гибко работать с несколькими функциями с различными параметрами - PullRequest
1 голос
/ 01 мая 2019

Я хочу использовать 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);
}

Есть ли способ сделать это?Если есть, можете ли вы помочь мне сделать это?

Спасибо:)

Ответы [ 2 ]

2 голосов
/ 01 мая 2019

В общем, вам нужно будет найти способ стандартизировать подпись для всех ваших обратных вызовов. Один из вариантов - использовать лямбда-выражения и использовать лямбда-захваты, чтобы уменьшить количество аргументов для ваших функций.

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

Обратите внимание, что одну и ту же функцию обхода нельзя было использовать для compare, поскольку вам необходимо одновременно пройти два дерева. И непонятно, что даже должен делать insert, но из комментария кажется, что это потребовало бы и одновременного обхода.

1 голос
/ 01 мая 2019

Одно из решений состоит в том, чтобы шаблонизировать вашу функцию перемещения, чтобы получить функциональный объект. Затем вместо указания параметров в функции 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);

Вот упрощенная версия , показывающая основы с использованием фиктивного класса.


Вы также можете использовать лямбду с этой техникой:

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