Home > Blockchain >  If I write a function pointer to use in BST template, can they take more than 1 object as argument?
If I write a function pointer to use in BST template, can they take more than 1 object as argument?

Time:08-07

I wrote a template for a binary search tree. I wish to overload the in-order traversal function. I can get it to work when the function pointer only takes in 1 object of class T. I would like it to use a function pointer that uses 2 integer values as well, so that I can pull the integers from outside the statement in main, then my function pointer will use those values to find an object in my BST. Is that possible? I'll show my code below.

For example, here is a typical implementation using just the T object:

template<class T>
void BSTTemplate<T>::inOrder(Node<T>* p) const
{
    if (p != nullptr)
    {
        inOrder(p->leftLink);
        cout << p->info << " ";
        inOrder(p->rightLink);
    }
}

template<class T>
void BSTTemplate<T>::inOrderTraversal() const
{
    inOrder(root);
}

When I activate this, my program spits out all the nodes in the BST in-order.

Here is the same code, but with a function pointer:

template<class T>
void BSTTemplate<T>::inOrder(Node<T>* p, void (*visit) (T&)) const
{
    if (p != nullptr)
    {
        inOrder(p->leftLink, *visit);
        (*visit) (p->info);
        inOrder(p->rightLink, *visit);
    }
}

template<class T>
void BSTTemplate<T>::inOrderTraversal(void (*visit) (T&)) const
{
    inOrder(root, *visit);
}

And now, in my main() I can run a statement such as:

//assume tree exists
Tree.inOrderTraversal(MyFunction);

where MyFunction is a void function such that

void MyFunction(MyObject& myObj)
{

    //does something
}

The goal for me is that I want to use a function with my Tree such that it takes in 2 integers from 'outside'. (basically user input)

I've tried something like this:

//overloading inOrder
template<class T>
void BSTTemplate<T>::inOrder(Node<T>* p, void (*visit) (T&,int&,int&)) const
{
    if (p != nullptr)
    {
        inOrder(p->leftLink, *visit);
        (*visit) (p->info);
        inOrder(p->rightLink, *visit);
    }
}

template<class T>
void BSTTemplate<T>::inOrderWithInputs(void (*visit) (T&,int&,int&)) const
{
    inOrder(root, *visit);
}

But when I try to call the traversal function in main() like this:

Tree.inOrderWithInputs(MyFunction(*arguments*));

The parser expects the arguments of an object of type T, an int, and another int. Previously when the function was only void MyFunction(MyObject& myObj), I need only use the function name as an argument. With multiple arguments to MyFunction itself, I don't have an object to fill it in with.

Ideally I want to do something like

Tree.inOrderTraversal(MyFunction(input1,input2));

where inputs are integers acquired from the user. Then the function manipulates those values to create a key, then the key is used to search the tree in-order.

Help me connect the dots please?

CodePudding user response:

In C it is better to use std::function than old style function pointers. std::function is a template you instantiate by specifying the return value and arguments (as many as you need).

It support passing a global function like you used in your code, as well as lambdas (you can also use a class method with std::bind).

When you call inOrderTraversal you should supply the arguments for the function as additional parameters (instead of using something like MyFunction(input1,input2) which actually invokes the function and passes it's return value).

See complete example:

#include <functional>
#include <iostream>


template <typename T>
class BSTTemplate
{
public:
    //---------------------vvvvvvvvvvvvv---------------------------- 
    void inOrderWithInputs(std::function<void(T&, int&, int&)> visit,
                           T& arg1, int& arg2, int& arg3) const  // <--- the arguments for invoking the function
    {
        // Invoke the function with the arguments:
        visit(arg1, arg2, arg3);
    }
};


void GlobalFunc(float& arg1, int& arg2, int& arg3)
{
    std::cout << "exceuting GlobalFunc with args: " << arg1 << ", " << arg2 << ", " << arg3 << std::endl;
}


int main() 
{
    BSTTemplate<float> bst;
    float f{ 0 };
    int i1{ 1 };
    int i2{ 2 };

    // Call with a global function:
    bst.inOrderWithInputs(GlobalFunc,
                          f, i1, i2);   // <--- the arguments for invoking the function

    // Call with a lambda:
    bst.inOrderWithInputs([](float& arg1, int& arg2, int& arg3) 
                          { std::cout << "exceuting lambda with args: " << arg1 << ", " << arg2 << ", " << arg3 << std::endl; },
                          f, i1, i2);   // <--- the arguments for invoking the function

    return 0;
}

Output:

exceuting GlobalFunc with args: 0, 1, 2
exceuting lambda with args: 0, 1, 2
  • Related