Question

I am trying to play with boost::lambda, but I bumped on an error I cannot figure out how to solve.

I have the feeling this is a beginner error, so please excuse my ignorance (and, I have to admit, my laziness for not reading the whole boost lamda documentation too).

It seems that in some cases using boost::bind (or maybe boost::lambda::bind?), is better suited than boost::lambda, but I am not sure if it can be applied here. I would like not having to write a separate function for if cond(arg1) arg2.insert(arg1) ;, as it would defeat the purpose; it would not be much better than a functor I guess.

I am using boost 1.35 with VC9 at work. The errors are at the cond() and insert() calling sites: "C2664: cannot convert parameter 1 from 'boost::lambda::placeholder1_type"

I replicated the problem with this snippet with g++ on my cygwin.

#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>

#include <boost/foreach.hpp>
#include <iostream>
#include <set>

void work(  boost::function<void(long)> doAction ) {
    long results[] = { 2, 5, 4 };
    BOOST_FOREACH( long r, results )
        doAction( r );
}

bool cond( long r ) { return r % 2 == 0 ; }

int main() {
    using namespace boost::lambda;
    std::set<long> myResults;
    work( 
        if_then( cond(_1) , boost::ref(myResults).get().insert(_1) ) );

    BOOST_FOREACH( long r, myResults )
        std::cout << r << "\n";
}

g++ errors:

lambda_test.cpp: In function ‘int main()’:
lambda_test.cpp:21:19: error: cannot convert ‘boost::lambda::placeholder1_type {aka const boost::lambda::lambda_functor<boost::lambda::placeholder<1> >}’ to ‘long int’ for argument ‘1’ to ‘bool cond(long int)’
if_then( cond(_1) , boost::ref(myResults).get().insert(_1) ) );
               ^
lambda_test.cpp:21:60: error: no matching function for call to ‘std::set<long int>::insert(boost::lambda::placeholder1_type&)’
if_then( cond(_1) , boost::ref(myResults).get().insert(_1) ) );

Any help would be appreciated,

Thanks

Was it helpful?

Solution

You're mixing deferred execution with immediate evaluation:

boost::ref(myResults).get().insert(_1)

Here, boost::ref(myResults) is not lazy, so .get() isn't either. The type of boost::ref(myResults).get() is just std::set<long> &, and that type's insert member function doesn't have an overload that takes a Boost Lambda placeholder.

I'm not well-versed in Boost Lambda (anymore) because I've moved to it's successor library, Boost Phoenix. Here's a 1-to-1 translation with fixes: Live On Coliru

#include <boost/phoenix.hpp>

#include <boost/foreach.hpp>
#include <iostream>
#include <set>

template <typename Action>
void work(  Action doAction ) {
    long results[] = { 2, 5, 4 };
    BOOST_FOREACH( long r, results )
        doAction( r );
}

bool cond( long r ) { return r % 2 == 0 ; }


int main() {
    namespace phx = boost::phoenix;
    using namespace phx::placeholders;

    std::set<long> myResults;
    work( 
        if_(phx::bind(cond, _1)) [ phx::insert(phx::ref(myResults), _1) ] );

    BOOST_FOREACH( long r, myResults )
        std::cout << r << "\n";
}

Prints

2
4

I'd suggest to look at Phoenix function adaptation, to avoid the bind expressions:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top