Search code examples
c++lambdaparameter-passinglazy-evaluationboost-spirit

Can't call a lazy lambda function with parameters via boost::phoenix::function


I tried to call boost::phoenix::function based on lambda function with parameters and failed. If I call it without parameters in such a way:

const auto closure = [](){
    cout<< "test" << endl;
};

typedef decltype(closure) ClosureType;
const boost::phoenix::function<ClosureType> lazyFunc (std::move(closure));
lazyFunc()();

all compiles nice. But when I declare at least one parameter of lambda:

const auto  closure = [](int& param)  { cout<<"Test" << param << endl; };

typedef decltype(closure) ClosureType;
const boost::phoenix::function<ClosureType> lazyFunc (std::move(closure));
lazyFunc(arg1)(a);

compilation fails with tremendous stack trace deep inside of boost::result_of


Solution

  • Assuming the error points to somewhere deep inside Boost.ResultOf (as seen in this demo), that would be because the closure type of a lambda expression does not implement the ResultOf protocol.

    A somewhat simple workaround to that is to define BOOST_RESULT_OF_USE_DECLTYPE, which makes boost::result_of bypass its own ResultOf protocol by instead using decltype to compute return types. This is not enabled by default because not many compilers (at the time of the release of Boost 1.51) are conformant enough for this feature to work; it is planned that this symbol be defined automatically (by Boost.Config) for those compilers that can deal with it for 1.52.

    Here is a demo of what it looks like to use Boost.Phoenix with a decltype-powered boost::result_of. I had to change the int& to int const& because i is apparently being forwarded as a const int. This appears to be a fundamental limitation of boost::phoenix::function, using boost::phoenix::val doesn't have this problem.