views:

157

answers:

4

This is the provided function template I'm trying to use:

template <class Process, class BTNode>
void postorder(Process f, BTNode* node_ptr)
{
   if (node_ptr != 0)
   {
      postorder( f, node_ptr->left() );
      postorder( f, node_ptr->right() );
      f( node_ptr->data() );
   }
}

This is my call, and the function I'm passing:

void city_db::print_bst() {
   postorder(&city_db::print, head);
}

void city_db::print(city_record target)
{
   std::cout << target.get_code();
}

This is the compile time (G++) error I get:

CityDb.cpp:85: instantiated from here

BinTree.template:80: error: must use ‘.’ or ‘->’ to call pointer-to-member function in ‘f (...)’

make: *** [CityDb.o] Error 1

This is in reference to the line f( node_ptr->data() ); in the function template.

This is for a Data Structures project. The assignment was modified so we don't need to pass a function to a function, but I've been interested in this for quite some time, and I feel like I almost have it here. I've exhausted Google and Lab TA's, so if StackOverflow has ideas, they would be greatly appreciated.

+3  A: 

You need an instance of city_db to call print on.

What you're passing is a pointer to a member function (think of it as a slot in the vtable), but you need a this pointer too. You could pass this in as another argument to the postorder function.

template <class Object, class Process, class BTNode>
void postorder(Object* obj, Process f, BTNode* node_ptr)
{
   if (node_ptr != 0)
   {
      postorder(obj, f, node_ptr->left() );
      postorder(obj, f, node_ptr->right() );
      ((obj)->*(f))( node_ptr->data() );
   }
}

See C++ FAQ Lite

Seb Rose
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5 This section of the FAQ gives some helpful pointers to making the syntax a little cleaner. In general I would prefer Thomas' answer.
Dolphin
Although I could probably modify it, I am treating BinTree as a large library to be left unmodified.This is a good look at what's going on underneath though, and thanks for the resource, added to delicious to check next time I have a problem.
Robert Kuykendall
+7  A: 

Your problem is that postorder accepts a function object that must be called this way:

f(arg);

You are passing in a pointer to member function. You should first call mem_fun to make a function object from the pointer to member:

std::mem_fun(&city_db::print)

The returned function object takes two arguments: the pointer to a city_db (the implicit this pointer), and the object to be printed. You can bind the first to this with bind1st, like this:

std::bind1st(std::mem_fun(&city_db::print), this)

And now you should be able to call postorder on it:

postorder(std::bind1st(std::mem_fun(&city_db::print), this), head);
Thomas
This took me a few minutes to understand this, but once it clicked it makes perfect sense. Thanks for breaking it down into manageable pieces. The final line solved the build errors.
Robert Kuykendall
A: 

You need to either make city_db::print() static or provide a city _db object.

drhirsch
A: 

As written

void city_db::print(city_record target)
{
   std::cout << target.get_code();
}

Does not depend on the class state. Declare it as a static function and compiler will not need this pointer to call it. FAQ on the topic.

BostonLogan
While this is true for this example, it sidesteps the whole issue of a pointer to a member function.
Dolphin