boost::bind, breaking functions composition, nested


boost::bind allows to use functions composition to achieve effect f(g(x)) easily.
But what to do when you actually need to bind something like f(x, a(y)).
Where function f accepts 2 arguments and the second one is a function.


We want this piece of code to work

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/assign.hpp>
#include <algorithm>
#include <vector>

void for_each_in_vector(std::vector<int> v, boost::function<void (int)> fx) {
  std::for_each(v.begin(), v.end(), fx);

void print_int(int i) {
  std::cout << i;

int main() {
  std::vector<std::vector<int> > vecs;

  std::for_each(vecs.begin(), vecs.end(),
                boost::bind(&for_each_in_vector, _1, 
                            boost::bind(&print_int, _1)));

So we actually are trying to call for_each_in_vector for every vector in vecs.
And that for_each_in_vector should call print_int for every int in that every vector.
In the 'unwrapped' code this will look like this

BOOST_FOREACH (std::vector<int> vec, vecs) {
  for_each_in_vector(vec, boost::bind(&print_int, _1));

And now take a look at that _1 placeholder. Due to the fact that boost::bind will try to make composition here
we will get argument 1 from the upper bind inserted as argument into the nested bind.
So by the fact this code tries to call something like this

BOOST_FOREACH (std::vector<int> vec, vecs) {
  for_each_in_vector(vec, boost::bind(&print_int, vec));  // note here vec instead of _1

When you will try to compile it you will get a big mess of templates errors and few usefull lines like this

./nested_bind.cpp:23:60:   required from here
/usr/include/boost/bind/bind.hpp:313:34: error: cannot convert ‘std::vector<int>’ to ‘int’ in argument passing
         unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);


What we actually want is to break that composition. How do boost::bind do it?
It just recognizes that it have got boost::bind as an argument and 'connectes' that placeholders within binds.
To make our code work we should fool boost bind and actually pass a function/functor instead of boost::bind as an argument.

std::for_each(vecs.begin(), vecs.end(),
              boost::bind(&for_each_in_vector, _1, 
                          boost::function<void (int)>(boost::bind(&print_int, _1, 2)))); // note boost::function here

Here we have used boost::function to wrap nested boost::bind.
So now top boost::bind will not recognize that nested bind and we will get isolated from each other placeholders.