views:

264

answers:

3

I need to call a method that expects a function pointer, but what I really want to pass to it is a functor. Here's an example of what I'm trying to do:

#include <iostream>
#include "boost/function.hpp"

typedef int (*myAdder)(int);

int adderFunction(int y) { return(2 + y); }

class adderClass {
  public:
    adderClass(int x) : _x(x) {}  
    int operator() (int y) { return(_x + y); }

  private:
    int _x;
};

void printer(myAdder h, int y) {
  std::cout << h(y) << std::endl;
}

int main() {
  myAdder f = adderFunction;

  adderClass *ac = new adderClass(2);
  boost::function1<int, int> g =
    std::bind1st(std::mem_fun(&adderClass::operator()), ac);

  std::cout << f(1) << std::endl;
  std::cout << g(2) << std::endl;
  printer(f, 3);
  printer(g, 4); // Is there a way to get this to work?
}

I haven't been able to find a way to get the last line, printer(g, 4), to compile. Is there a way to get this to work? The only things in my control are the method "main" and the class "adderClass".

A: 

like so:

template<typename AdderT>
void printer(AdderT h, int y) {
  std::cout << h(y) << std::endl;
}

Also, you don't need the boost::function. You can just do:

  adderClass ac(2);
  std::cout << f(1) << std::endl;
  std::cout << ac(2) << std::endl;
  printer(f, 3);
  printer(ac, 4);
shoosh
That would work, but (I forgot to mention), the method "printer" is in code I cannot change.
JamieC
All that's in my control is the method "main" and the class "adderClass".
JamieC
A: 

While a boost function behaves like a normal function pointer, it is a different type. So you can't just assign a boost function to a function pointer.

In your code you could simply replace

typedef int (*myAdder)(int);

with

typedef boost::function1< int, int > myAdder;

and everything would work.

Pieter
+2  A: 

Ok, here's another try:

class CallProxy
{
public:
    static adderClass* m_instance;
    static int adder(int y)
    {
     return (*m_instance)(y);
    }
};

adderClass* CallProxy::m_instance = NULL;


int main() {
    myAdder f = adderFunction;

    adderClass ac(2);

    std::cout << f(1) << std::endl;
    std::cout << ac(2) << std::endl;
    printer(f, 3);
    CallProxy::m_instance = &ac;
    printer(CallProxy::adder, 4); 
}

The trouble is that you have printer compiled as having to receive a function pointer and nothing else so you must send it a function pointer. With a function pointer you have no one to hold your instance. So this solution does that by using a static data member.

Mind you that this makes this code not thread safe. Two threads which execute main at the same time may put two different things in m_instance.

shoosh
It's also not re-entrant: if `printer` calls `main` you're in trouble. But I think it's the best that can be done given the constraints, at least portably. For non-portable solutions, you could for example generate code on the fly.
Steve Jessop
@Steve Jessop:Anything that calls `main()` causes undefined behavior anyway (§3.6.1/2:"The function main shall not be used (3.2) within a program.")
Jerry Coffin
@Jerry Coffin - do try to look beyond the the limited confines of this silly example.
shoosh