Search code examples
c++function-pointersdepth-first-searchbreadth-first-searchfunction-parameter

C++ Passing Parameters for a Function Pointer that is a Parameter to Another Function?


I want to write Breadth-First Search and Depth-First Search functions for a graph. But these functions should be able to take a function as a parameter so I can pass each node in the graph to the function as I find it in the search. Because some of these functions need parameters of their own, how do I pass those secondary parameters?

Pseudocode Example:

void BreadthFirstSearch(node* n, void (*func)(node*)){
     // do the search stuff
     // run the function on each node
     func(current_node);
}
void SetColor(node* n, color c){ // set color... }
void SetNumber(node* n, int i){ //set number... }

int main(){
    // make the graph...
    // set the color...
    BreadthFirstSearch(n, SetColor, WHERE DO I PUT THE COLOR PARAMETER?);

I have figured out how to pass a function pointer to my search functions, but the function pointer takes no extra arguments, so SetColor(node* n) can change the color of each node its given during the search, but I have to hard code the color into the SetColor function.

Here is a stripped down version of my code so you can see what I'm trying so far:

void BFS(node* n, void (*func)(node*)){
    // make a visited set
    std::set<node*> visited = std::set<node*>();
    // make a frontier queue
    std::queue<node*> frontier = std::queue<node*>();
    frontier.push(n);

    while(!frontier.empty()){
        // get current node from frontier
        node* current = frontier.front();
        frontier.pop();
        // add current node to visited set
        visited.insert(current);
        // get neighbors from current node and add to frontier...
        
        // run the function on the current node
        func(current);
    }
}

void set_color(node* n){
    // hard code the color because I don't know what I'm doing
    n->color = (255, 0, 0);
}

int main(){
    // do stuff
    // run the search with set_color function
    BFS(start_node, set_color);
    // do more stuff
}

I have also tried looking up variadic functions, thinking that I could pass the color parameter as the extra parameters. But I don't understand the variadic function syntax well enough. Might still be part of the solution though.


Solution

  • The easiest option is to pass a callback function that is a wrapper around the real function and knows some of the arguments:

    int main() {
        // ...
        BFS(start_node, [](node* n) { set_color(n, Color::RED); });
        // ...
    }
    

    That will work perfectly fine with a hard-coded color since non-capturing lambdas can be converted to function pointers.

    If you want to determine the color dynamically you'll need something more complex than a raw function pointer since capturing lambdas can't be converted to function pointers. std::function is perhaps the easiest option to use, but it has a runtime overhead that isn't necessarily needed if the function you pass to BFS is known at compile time.

    Instead, you can make BFS a function template, and make the callback type a template parameter:

    template <typename Func>
    void BFS(node* n, Func&& func){
        // ...
        // run the function on the current node
        func(current);
        // ...
    }
    

    With that change, you can pass any function-like type to BFS, including a capturing lambda:

    int main() {
        // ...
        Color color = get_desired_color();
        BFS(start_node, [color](node* n) { set_color(n, color); });
        // ...
    }