Search code examples
c++boostlambdaboost-bind

how do I compose multiple functors using boost bind?


I've got a situation where I have a series of member functions which produce simple information on a target object:

double MyDoc::GetX(thing)
double MyDoc::GetY(thing)
etc.

I've made some "pretty formatting" member functions in the same class:

string MyDoc::PrintOne(thing, std::function<double (THING*)>)

You'll notice that the pretty-printer function takes a data-function - i.e. it is composable so that I can create various types of information about a target and produce a "pretty print" string for it.

In direct usage, this technique works beautifully.

However, what I really want for my current application is to compose multiple layers of such entities - i.e. effectively create a functor (function object) for the above composition as a whole, such that I can specify pretty-printer function, and it's data-acquisition function, and call that later. Pattern is z(x) -> f(x, g(x)):

auto Z = [&] (THING* thing) {
    return boost::bind(
        &MyDoc::PrintOne,
        this,
        _1,
        boost::bind(MyDoc::GetX, this, _1));
}

And here is where I run into problems. I am going in circles trying to get the syntax right, or maybe I'm getting confused with the boost::bind syntax versus the C++ lambda syntax, or maybe I'm just fundamentally misunderstanding something?

Basically, I want to compose a function Z which takes a THING* and another function X which also takes a THING* and, using logic of its own, produces a string output for a given THING*.

I have variations - some take two data-accessor type functions, or maybe a bool + data accessor. Doesn't really matter - the bottom line should be the same:

How do I compose Z where Z -> F(x, G(x))?

Thanks for any and all help!


Solution

  • boost::bind (and std::bind) eagerly evaluates nested bind expressions, so what you have would match a signature string MyDoc::PrintOne(THING*, double). To prevent eager evaluation and return the nested bind expression directly (suitable for constructing a std::function<>), use boost::protect:

    boost::bind(
        &MyDoc::PrintOne,
        this,
        _1,
        boost::protect(boost::bind(&MyDoc::GetX, this, _1))
    )
    

    This is outlined in the section of the documentation titled "using nested binds for function composition".