views:

40

answers:

2

Hello everyone,

Most of my classes have lists as private data members. As such, most of them also have adder/remover public members. I noticed I was writing basically the same thing for each of the adders, so I thought I'd turn it into a template.

Here's what I've got:

template <class N, class I>
void add(N element, std::list<N> & container, I (*f)(void),
  std::string successmsg, std::string exceptmsg) {
 typename std::list<N>::iterator it;

 it = find(container.begin(), container.end(), element);
 try {
  if(it != container.end())
   throw DuplicateElement<I>(element->(*f));
 }
 catch (DuplicateElement<I>&){
  std::cout << exceptmsg;
  pause(PAUSE_MESSAGE);
  return;
 }
 container.push_back(element);
 std::cout << successmsg;
}

Let me just explain this one, its parameters (in order) are the element to add, the container which the element shall be added to, a function present on the element class that returns its unique ID (a code, a license plate, whatever), a success message and an exception message.

Sample usage:

void Aeroporto::addCompanhia(CompanhiaAerea* companhia) {

 std::string success = "Companhia aérea adicionada com sucesso!";
 std::string except = "Companhia aérea já existente!";
 add(companhia, companhias, getSigla, success, except);
// std::list<CompanhiaAerea*>::iterator it;
//
//  it = find(companhias.begin(), companhias.end(), companhia);
//  try{
//   if(it != companhias.end())
//    throw DuplicateElement<std::string>(companhia->getSigla());
//  }
//  catch (DuplicateElement<std::string>&){
//     std::cout << "Companhia aérea já existente!";
//     pause(PAUSE_MESSAGE);
//     return;
//  }
//
//  companhias.push_back(companhia);
//  std::cout << "Companhia aérea adicionada com sucesso!";

}

When I try to compile this, I get the following:

..\src\/headers/template.h: In function 'void add(N, std::list<N>&, I (*)(), std::string, std::string)':
..\src\/headers/template.h:23:29: error: expected primary-expression before '(' token
..\src\/headers/template.h:23:39: error: expected unqualified-id before '(' token
..\src\aeroporto.cpp: In member function 'void Aeroporto::addCompanhia(CompanhiaAerea*)':
..\src\aeroporto.cpp:76:54: error: no matching function for call to 'add(CompanhiaAerea*&, std::list<CompanhiaAerea*>&, <unresolved overloaded function type>, std::string&, std::string&)'

I require your assistance since it's not particularly easy to google for this kind of stuff.

Thank you for your time!

+2  A: 

You do not want to pass a function pointer, but a member function pointer. They are quite different in C++ (basically the implicit this argument). This is a simple test case on how free functions, static member functions and non-static member functions can be passed around. You will have to complete it with the template part:

struct test {
   void foo() { std::cout << "test::foo" << std::endl; }
   static void bar() { std::cout << "test::bar" << std::endl; }
};
void foo() { std::cout << "foo" << std::endl; }

void call_function( void (*f)() )
{
   f();
}
void call_member( test & t, void (test::*f)() )
{
   t.*f();
   (&t)->*f();
}
int main() 
{
   test t;
   call_function( &foo );        // free function
   call_function( &test::bar );  // equivalent for static member function
   call_member( t, &test::foo ); // but not for member function
}
David Rodríguez - dribeas
Thank you, I learned a lot about passing routines as args.
Francisco P.
+3  A: 

Because you want to use a method, you have to use a pointer-to-member-function:

template <class N, class I>
void add(N* element, std::list<N*>& container, I (N::*f)() const,
  std::string successmsg, std::string exceptmsg) {
 typename std::list<N*>::iterator it;

 it = find(container.begin(), container.end(), element);
 try {
  if(it != container.end())
   throw DuplicateElement<I>((element->*f)());
//...
//...
add(companhia, companhias, &CompanhiaAerea::getSigla, success, except);
//...

Note how I had to change the way N is used, in order to get the right type for f.

Roger Pate
Francisco P.
@Francisco: The const is part of the signature, updated my answer.
Roger Pate
Thanks a bunch, I learned a lot about passing functions as args with this problem.
Francisco P.