Catskul
Catskul

Reputation: 19239

Is it possible to use boost::bind to effectively concatenate functions?

Assume that I have a boost::function of with an arbitrary signature called type CallbackType.

I'm open to any potential solution, but here's a...

...Hypothetical example using some magic template:

Template<typename CallbackType>
class MyClass
{
    public:
        CallbackType doBoth;

        MyClass( CallbackType callback )
        {
            doBoth = bind( magic<CallbackType>, 
                             protect( bind(&MyClass::alert, this) ),   
                               protect( callback )                    );
        }

        void alert()
        {
            cout << "It has been called\n";
        }
};

void doIt( int a, int b, int c)
{
    cout << "Doing it!" << a << b << c << "\n";
}

int main()
{
    typedef boost::function<void (int, int, int)> CallbackType;

    MyClass<CallbackType> object( boost::bind(doIt) );

    object.doBoth();

    return 0;
}

Upvotes: 6

Views: 1389

Answers (2)

Rob Kennedy
Rob Kennedy

Reputation: 163287

Boost already provides a way to create a sequence of bound functions. Use Lambda's comma operator.

using namespace boost::lambda;
MyClass mc;
CallbackType object = (bind(&MyClass::alert, mc), bind(doIt, _1, _2, _3));
object(1, 2, 3);

That will create a new functor, object. When you invoke that functor with three arguments, it will in turn call mc.alert() before passing those arguments to doIt. The parentheses are important.

For my example above to work, you'd need alert to be a const function. If it needs to be non-const, then either pass a pointer to mc, or wrap it with boost::ref(mc). And you'll need to use Boost.Lambda's bind rather than Boost.Bind's; the latter isn't compatible with Lambda's function-combining operators (comma, in particular).

Upvotes: 8

Potatoswatter
Potatoswatter

Reputation: 137810

template< class Callback >
struct pre_caller {
    Callback c;

    pre_caller( Callback in_c ) : c( in_c ) {}

    void alert() {} // or an instance of a functor

    operator()
    { alert(); c(); }

    template< class T1 >
    operator( T1 a ) // not sure if/what qualification to add to a
    { alert(); c( a ); } // or whether to attempt to obtain from
                         // function_traits<Callback>?
    template< class T1, class T2 >
    operator( T1 a, T2 b )
    { alert(); c( a, b ); }

    template< class T1, class T2, class T3 >
    operator( T1 a, T2 b, T3 c )
    { alert(); c( a, b, c ); }

    // ad nauseam... and I mean nausea, maybe read up on Boost Preprocessor.
};

Boost Bind uses a lot of preprocessor hacking for its variadic voodoo, and unfortunately I don't think it provides a pattern or tools for head-patching which is essentially what this is.

Upvotes: 1

Related Questions