I am fairly new to using algorithm
and functional
in C++. I need to do tree traversal and perform a function for each element. See the code below.
This works but a I have few things I don't like and perhaps can do better. Note that I am limited to a fairly old version of g++ (4.4.7) and cannot use lambda functions.
I use a wrapper function do_walk
and std::bind
to call the member function walk
on each element. Is there a way to avoid the wrapper function and directly call the member function?
I use a typedef for the callback function UnaryFunction
. I would prefer to use a templated version of walk
. However, when I change the code to use a template I get the following compilation error: error: no matching function for call to 'bind(<unresolved overloaded function type>, std::_Placeholder<1>&, void (*&)(const Elem&))'
. Is it possible to use templates in this context?
Perhaps there is an alternative to std::for_each
that is better suited for this kind of tree traversal?
My code so far:
#include <list>
#include <algorithm>
#include <functional>
struct Elem;
typedef void (*UnaryFunction)(const Elem&); // (2)
struct Elem
{
std::list<Elem> children; // Some container, std::list for now.
//template< class UnaryFunction > // (2)
void walk(UnaryFunction f) const
{
// Walk all children.
std::for_each(
children.begin(),
children.end(),
std::bind(do_walk, std::placeholders::_1, f)); // (1)
// Walk this object.
f(*this);
}
//template< class UnaryFunction > // (2)
static void do_walk(const Elem& elem, UnaryFunction f) // (1)
{
elem.walk(f);
}
};
void pretty_print(const Elem& elem)
{
// Pretty print element.
}
int main()
{
Elem root;
// Create tree somehow.
root.walk(pretty_print);
return 0;
}
std::bind
is capable of invoking member functions (passing the first argument to the implicit this
parameter), so you can replace do_walk
with this:
std::bind(&Elem::walk, std::placeholders::_1, f)
The problem with making walk
a template is that at the time of bind
ing, it's not clear which instantiation should be used. You can disambiguate that by explicitly specifying the template argument:
std::bind(&Elem::walk<UnaryFunction>, std::placeholders::_1, f)
I believe std::for_each
is fine.
[Live example] using gcc 4.4.7
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With