9

I'm attempting to pass an std::function via a method like so:

class dispatch
{
  public:
     deliver( std::function<void ( void )> task );
};

This works as expected. However i wish to pass arguments to some of the methods supplied as the task but would prefer not to have to create overloads for all the different function< ... > forms.

for example is it at all possible just to create a method like follows

deliver( std::function& task );

and just invoke with

dispatch->deliver( bind( &Object::method, X ) );

or

dispatch->deliver( bind( &Object::method, X, arg1, arg2 ) );

etc...

Thanks for everyone's input. It would appear my real fault is with calls to dispatch->deliver with the additional argument also being a bind call.

dispatch->deliver( bind( &Object::method1, X1, bind( &Object::method1, X2 ) );

error: /usr/include/c++/v1/functional:1539:13: error: no matching function for call to '__mu_expand' return __mu_expand(__ti, __uj, __indices());

LNJ
  • 304
  • 2
  • 13
Ben Crowhurst
  • 8,204
  • 6
  • 48
  • 78

3 Answers3

10

std::function<void(void)> is already polymorphic, that's the whole point of it. So those two last snippets will work (as long as the functor bind returns can be called with no arguments, and returns nothing, of course), without changing what you already have.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
3

Yes, it is possible as long as you use bind to generate compatible function objects:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <list>
#include <string>

typedef boost::function<void(void)> fun_t;
typedef std::list<fun_t> funs_t;

void foo()
    { std::cout <<"\n"; }
void bar(int p)
    { std::cout<<"("<<p<<")\n"; }
void goo(std::string const& p)
    { std::cout<<"("<<p<<")\n"; }

void caller(fun_t f)
    { f(); }

int main()
{
    funs_t f;
    f.push_front(boost::bind(foo));
    f.push_front(boost::bind(bar, int(17)));
    f.push_front(boost::bind(goo, "I am goo"));

    for (funs_t::iterator it = f.begin(); it != f.end(); ++it)
    {
        caller(*it);
    }

    return 0;
}

(Note, I use Boost.Function and Boost.Bind, but there should be no difference to use of std::bind and std::function.)

mloskot
  • 37,086
  • 11
  • 109
  • 136
2
class dispatch
{
  public:
     template <typename ... Params>
     deliver( std::function<void (Params && p...)> task, Params && p )
     {
         task(std::forward(p)...);
     }
};

I haven't compiled this (corrections welcome!), but the idea should work.

dispatch->deliver( bind( &Object::method, X ) );
dispatch->deliver( bind( &Object::method, X, arg1, arg2 ) ); // OR!
dispatch->deliver( bind( &Object::method, X ), arg1, arg2 );

The one thing I'm unclear about is how this behaves if Object::method has defaulted params instead of overloads.

Michael Price
  • 8,088
  • 1
  • 17
  • 24
  • +1: One nitpick, It might be more efficient to pass the std::function as const reference. – mirk Oct 28 '11 at 09:03
  • @DirkM You are right, but since the OP didn't do it, I chose not to as well. He could be doing something in that deliver method that isn't involved with "delivery". I hope not though. – Michael Price Oct 29 '11 at 03:52