Search code examples
c++boostboost-bindboost-function

Boost function and boost bind: Bind the return value?


This is related to this previous question: Using boost::bind with boost::function: retrieve binded variable type.

I can bind a function like this:

in .h:

class MyClass
{
    void foo(int a);
    void bar();
    void execute(char* param);
    int _myint;
}

in .cpp

MyClass::bar()
{
    vector<boost::function<void(void)> myVector;
    myVector.push_back(boost::bind(&MyClass::foo, this, MyClass::_myint);
}
MyClass::execute(char* param)
{
    boost::function<void(void)> f  = myVector[0];
    _myint = atoi(param);
    f();
}

But how can I bind a return value ? i.e.:

in .h:

class MyClass
{
    double foo(int a);
    void bar();
    void execute(char* param);
    int _myint;
    double _mydouble;
}

in .cpp

MyClass::bar()
{
    vector<boost::function<void(void)> myVector;
    //PROBLEM IS HERE: HOW DO I BIND "_mydouble"
    myVector.push_back(boost::bind<double>(&MyClass::foo, this, MyClass::_myint);
}
MyClass::execute(char* param)
{
    double returnval;
    boost::function<void(void)> f  = myVector[0];
    _myint = atoi(param);
    //THIS DOES NOT WORK: cannot convert 'void' to 'double'
    // returnval = f();
    //MAYBE THIS WOULD IF I COULD BIND...:
    // returnval = _mydouble;

}

Solution

  • If what you want is a nullary function that returns void but assigns a value to _myDouble with the result of foo() before doing so, then you cannot do this easily with just Boost.Bind. However, Boost has another library specifically catered to this sort of thing -- Boost.Phoenix:

    #include <iostream>
    #include <vector>
    #include <boost/function.hpp>
    #include <boost/phoenix/phoenix.hpp>
    
    struct MyClass
    {
        MyClass() : _myVector(), _myInt(), _myDouble() { }
        void setMyInt(int i);
        void bar();
        void execute();
    
    private:
        double foo(int const a) { return a * 2.; }
    
        std::vector<boost::function<void()> > _myVector;
        int _myInt;
        double _myDouble;
    };
    
    void MyClass::setMyInt(int const i)
    {
        _myInt = i;
    }
    
    void MyClass::bar()
    {
        using boost::phoenix::bind;
    
        _myVector.push_back(
            bind(&MyClass::_myDouble, this) =
                bind(&MyClass::foo, this, bind(&MyClass::_myInt, this))
        );
    }
    
    void MyClass::execute()
    {
        if (_myVector.empty())
            return;
    
        _myVector.back()();
        double const returnval = _myDouble;
        std::cout << returnval << '\n';
    }
    
    int main()
    {
        MyClass mc;
        mc.bar();
    
        mc.setMyInt(21);
        mc.execute();      // prints 42
        mc.setMyInt(3);
        mc.execute();      // prints 6  (using the same bound function!)
                           // i.e., bar has still only been called once and
                           // _myVector still contains only a single element;
                           // only mc._myInt was modified
    }