Member variable comparator factory

J

Juha Nieminen

Assume you have some kind of struct with several member variables. For
the same of simplicity, let's assume that your struct is like:

struct Info
{
str::string name;
int age;
};

Now, suppose you have, for example, a vector of objects of type Info,
and you would like to be able to sort the vector either by name or by age.
Bummer, you'll have to write two comparators for this. However, wouldn't
it be nice if you could just do something like this:

// Sort the array by name:
std::sort(array.begin(), array.end(),
makeMemberComparator(&Info::name);

or

// Sort the array by age:
std::sort(array.begin(), array.end(),
makeMemberComparator(&Info::age);

That way you wouldn't have to write a new comparator function every time
you need to sort by some member variable of some struct.

Well, it is very possible to implement a 'makeMemberComparator()' like
above. It happens like this:

//--------------------------------------------------------------------
template<typename Object_t, typename Var_t>
class MemberVarComparator
{
typedef const Var_t Object_t::*MemberVarPtr_t;
MemberVarPtr_t memberVarPtr;

public:
MemberVarComparator(MemberVarPtr_t ptr): memberVarPtr(ptr) {}

bool operator()(const Object_t& obj1, const Object_t& obj2) const
{
return obj1.*memberVarPtr < obj2.*memberVarPtr;
}
};

template<typename Object_t, typename Var_t>
MemberVarComparator<Object_t, Var_t>
makeMemberComparator(const Var_t Object_t::*memberVarPtr)
{
return MemberVarComparator<Object_t, Var_t>(memberVarPtr);
}
//--------------------------------------------------------------------

Of course this will always sort using operator<. I'll leave it as an
exercise to enhance the class and the makeMemberComparator() function to
support specifying the comparison type (such as eg. std::greater), the
default being, naturally, std::less.
 
N

Noah Roberts

Assume you have some kind of struct with several member variables. For
the same of simplicity, let's assume that your struct is like:

struct Info
{
str::string name;
int age;
};

Now, suppose you have, for example, a vector of objects of type Info,
and you would like to be able to sort the vector either by name or by age.
Bummer, you'll have to write two comparators for this. However, wouldn't
it be nice if you could just do something like this:

// Sort the array by name:
std::sort(array.begin(), array.end(),
makeMemberComparator(&Info::name);

or

// Sort the array by age:
std::sort(array.begin(), array.end(),
makeMemberComparator(&Info::age);

With boost or in the C++0x you can do this with bind:

std::sort(cont.begin(), cont.end(), bind(&Info::name, _1) < bind
(&Info::name, _2));

or

std::sort(cont.begin(), cont.end(), bind(&Info::age, _1) < bind
(&Info::age, _2));

This works with boost anyway. Not sure if the next standard will have
the < operator for binders defined. If not, you could always bind
std::less<> like so:

bind(std::less<std::string>, bind(&Info::name,_1), bind(&Info::name, _
2))

I don't know how I'd live without bind. I used to have to where I work
but I made a loud enough stink for long enough that we get to use it
now. No more need to hand build custom things like what you just did
for simple tasks.

Great example if you're stuck without bind though.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top