views:

150

answers:

3

Hello, I have to pass function into pointer. For this purposes I'm using boost::function. The function which catches the pointer is overloaded for different signatures. For example:

void Foo(boost::function<int ()>) { ... }
void Foo(boost::function<float ()>) { ... }
void Foo(boost::function<double ()>) { ... }

Now I wanna pass some class-method pointer there:

class test
{
   public:
      float toCall() { };
};

class Wrapper
{
  Wrapper() {
    test obj;
    Foo(boost::bind(&test::toCall, this));
  }
};


error: no matching function for call to ‘Foo(boost::_bi::bind_t<float, boost::_mfi::mf0<float, test>, boost::_bi::list1<boost::_bi::value<Wrapper*> > >)’
    note: candidates are: Foo(boost::function<float()>&)
+1  A: 

boost::bind does not return a boost::function object. It returns an object of unspecified type that can be used as a functor with corresponding number of parameters.

While boost::function can be conversion-constructed from the result of boost::bind, the overload resolution in this case is "too complex" for C++. (Removed my bad example which didn't really illustrate the right problem).

AndreyT
For boost function, the scenario is even more evil than this. It's like `template<typename T> struct A { template<typename U> A(U); };` now, *that* looks unsolvable to me xD Note that you *can* convert if you had only one function. The difficulty is to *compare* two such conversion sequences. In the boost::function case, this is downright impossible, and in your case, it could be possible but it's too complex for over-res to bother with.
Johannes Schaub - litb
@Johannes Schaub: You are right. My example was illustrating a completely different problem: ambiguity instead of "unsolvability" :)
AndreyT
+6  A: 

Nonono this cannot work. Because boost::function<...> has a templated constructor to accept any and all types. Compatibility with the call signature is checked later on. Overload resolution cannot resolve this.

Also, i think you want to pass &obj instead of this. Try converting explicitly:

Foo(boost::function<float ()>(boost::bind(&test::toCall, &obj)));

This is utterly ugly though so you may want to introduce a typedef

void Foo(FloatHandler) { ... }
...
FloatHandler f(boost::bind(&test::toCall, &obj));
Foo(f);

Or ultimately you could make Foo a template that accepts just any callable type T. I suspect that may be the simplest, because in the general case i suspect you don't know to what boost::function<...> you need to cast to. And how about folks that want to return a std::complex<>. So...

template<typename T>
void Foo(T) { ... }
...
Foo(boost::bind(&test::toCall, &obj));

Hope this helps.

Johannes Schaub - litb
+2  A: 

In the line

Foo(boost::bind(&test::toCall, this));

this is of type Wrapper. But the bind can't find a toCall method on it.

Here's a fixed-up version (complete, compiles on g++ 4.3.2) which is probably what you're trying to do:

#include <boost/bind.hpp>
#include <boost/function.hpp>

void Foo(boost::function<int()>) {}
void Foo(boost::function<float()>) {}
void Foo(boost::function<double()>) {}

struct test {
  float toCall() {return 0.0f;}
};

int main(int,char**) {
  test obj;
  boost::function<float()> tgt=boost::bind(&test::toCall,obj);
  Foo(tgt);
  return 0;
}

As AndreyT's answer notes, the return type of bind is... a bit odd, hence the explicit coercion to an appropriate function type.

timday