Search code examples
c++boostboost-bindfunctor

Perform argument substitution on nested boost::bind without composition


Suppose I have a function which takes a nullary functor as an argument:

void enqueue( boost::function<void()> & functor );

I have another function which takes an int and does something internally:

void foo( int a);

I would like to nest, but not compose, these together so that I get a functor with the signature:

boost::function<void(int)> functor

Which when called with a value - say 4 - performs the following:

enqueue( boost::bind(&foo, 4) )

My first attempt was the following:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::bind(&foo,_1))

This fails because bind performs composition when given a nested bind. foo was first called, then the value void was "returned" to enqueue, which fails.

My second attempt was the following:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::protect( boost::bind(&foo, _1) ) )

This failed because enqueue accepts a nullary, not unary functor.

Can what I'm seeking be done?

Other information:

  • This is basically identical to the unanswered boost forum question from 6 years ago: http://lists.boost.org/boost-users/2004/07/7125.php
  • Some reading suggests that using boost::lambda::bind with boost::lambda::unlambda and boost::lambda::protect may do what I'm seeking. Unfortunately boost::lambda has an unacceptably low number of allowed placeholders (3), and high compile-time overhead.

Solution

  • Interesting question...

    What you basically want is a "bound call to bind". In the same manner than binding a call to foo(x, y) is written bind(&foo, x, y), binding a call to bind(&foo, x) should be like bind(&bind, &foo, x). However, taking the address of an overloaded function quickly gets ugly and, as boost::bind has more overloads than I could count, it gets pretty ugly:

    // One single line, broken for "readability"
    boost::function<void(int)> f = boost::bind(
      &enqueue, 
      boost::bind(
        static_cast<
          boost::_bi::bind_t<
            void, void(*)(int), boost::_bi::list_av_1<int>::type
          >
          (*)(void(*)(int), int)
        >(&boost::bind), 
        &foo, 
        _1
      )
    );
    

    You'll probably agree that, while "interesting", the above won't win readability contests. Separating the obtention of the proper bind overload from the rest makes things a bit more manageable:

    boost::_bi::bind_t<void, void(*)(int), boost::_bi::list_av_1<int>::type>
      (*bind_foo)(void(*)(int), int) = &boost::bind;
    
    boost::function<void(int)> q = boost::bind(&enqueue, boost::bind(bind_foo, &foo, _1));
    

    but I still hesitate to recommend it ;)

    Edit:

    Answering the OP's comment about how/if C++0x would help to clean the syntax: It does:

    auto f = [](int i){enqueue([=](){foo(i);});};