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