views:

217

answers:

2

Hi, I am trying to use boost lambda to avoid having to write trivial functors. For example, I want to use the lambda to access a member of a struct or call a method of a class, eg:

#include <vector>
#include <utility>
#include <algorithm>
#include <boost/lambda/lambda.hpp>

using namespace std;
using namespace boost::lambda;

vector< pair<int,int> > vp;

vp.push_back( make_pair<int,int>(1,1) );
vp.push_back( make_pair<int,int>(3,2) );
vp.push_back( make_pair<int,int>(2,3) );

sort(vp.begin(), vp.end(), _1.first > _2.first );

When I try and compile this I get the following errors:

error C2039: 'first' : is not a member of 'boost::lambda::lambda_functor<T>'
        with
        [
            T=boost::lambda::placeholder<1>
        ]
error C2039: 'first' : is not a member of 'boost::lambda::lambda_functor<T>'
        with
        [
            T=boost::lambda::placeholder<2>
        ]

Since vp contains pair<int,int> I thought that _1.first should work. What I am doing wrong?

+5  A: 

What you want is something akin to:

#include <boost/lambda/bind.hpp> // new header

// typedefs make code easier
typedef pair<int,int> pair_type;
typedef vector<pair_type> vector_type;

vector_type vp;

vp.push_back( make_pair(1,1) ); // don't specify template arguments!
vp.push_back( make_pair(3,2) ); // the entire point of make_pair is
vp.push_back( make_pair(2,3) ); // to deduce them.

sort(vp.begin(), vp.end(),
        bind(&pair_type::first, _1) > bind(&pair_type::first, _2) );
GMan
I like your point with the typedefs, but you're still repeating the <int, int> a lot. You can do `vp.push_back( vector_type::value_type(1,1) );` to make future maintenance easier (only one line to change if you want to use longs instead).
Tim
@Tim: Oops, I didn't even consider that code, that's just copy-paste. I would do...this. (Edit.)
GMan
The trouble with `make_pair` is that if it's alright with `int` try having a `vector< std::pair<float,float> >` and you'll have to precise `f` near each of your figures... argument deduction is messy with numerics :/
Matthieu M.
+4  A: 

According to this, I believe the syntax is

sort(vp.begin(), vp.end(), 
bind(&pair<int,int>::first, _1) > bind(&pair<int,int>::first, _2));

However, I'd like to point out the (not so?) obvious -- sort(vp.begin(), vp.end()); will basically do the same thing. pairs are by default sorted by their first argument, then by the second. Since you're using sort (which is not stable), you're going to have all the pairs sorted by first, and then the pairs with equal first are going to be in more or less random order.

If you want to preserve the order when the first elements are equal, you should use stable_sort instead.

rlbond
+1 for pre-existing comparators for `pair`.
GMan
Excellent, thanks. (Regarding pair - I had just it to simplify the code)
hamishmcn
I had a feeling this was just an example, but I wanted to make sure :)
rlbond