Grim Fandango
Grim Fandango

Reputation: 2426

how to generate a compare function from a pointer to member function?

Writing compare functions for STL algorithms & containers is tedious.

For simple objects such as this,

struct Person
{
    int id;
    string name;
    string surname;
    string get_full_name(); // name then surname
};

I have to type the same function call for both lhs and rhs:

vector<Person> v = { ... };
std::sort( v.begin(), v.end(), [](const Object &lhs, const Object &rhs) {
    return lhs.get_full_name() < rhs.get_full_name();   // tedious
} );

I would like to be able to compose a compare function/functor using a pointer-to-member-function or pointer-to-member-data. Maybe like so:

std::sort( v.begin(), v.end(), make_compare_functor( &Object::get_full_name ));
std::sort( v.begin(), v.end(), make_compare_functor( &Object::surname ));

I've tried to implement it like so:

template <class R, class T>
struct CompareFunctor {
    R (T::*fp)();
    bool operator() (const T& lhs, const T& rhs) { 
           return lhs->*fp() < rhs->*fp();
    }
};

// helper function
template <class R, class T>
CompareFunctor<R,T> make_compare_functor(R(T::*fp)()) {
    return CompareFunctor<R,T> { fp };
}

but it fails to instantiate T for any of these cases

auto functor1 = make_compare_functor( &Person::get_full_name );
auto functor2 = make_compare_functor( &std::string::size );

(the error message is like: 'make_compare_functor': no matching overloaded function found ... note: could be 'const Person' or 'Person')

can anybody guide me how to to compose a compare function/functor using a pointer-to-member-function please?

It should preferably be STL based -- no Boost or another library.

Upvotes: 0

Views: 68

Answers (1)

cigien
cigien

Reputation: 60208

You're on the right track, but you'll need to overload make_compare_functor to accept both a pointer-to-member-function, as well as a pointer-to-member. In addition, you'll need to write a CompareMember that compares pointer-to-members, similar to how CompareFunctor compares pointer-to-member-functions:

// compare pointer to member function
template <class R, class T>
struct CompareFunctor {
    R (T::*fp)() const;
    bool operator() (const T& lhs, const T& rhs) { 
           return (lhs.*fp)() < (rhs.*fp)();
    }
};

// compare pointer to member
template <class T, class M>
struct CompareMember {
    M T::*mp;
    bool operator() (const T& lhs, const T& rhs) { 
           return lhs.*mp < rhs.*mp;
    }
};

// helper function : compare pointer to member function
template <class R, class T>
CompareFunctor<R,T> make_compare_functor(R(T::*fp)() const) {
    return CompareFunctor<R,T> { fp };
}

// helper function : compare pointer to member 
template <class T, class M>
CompareMember<T, M> make_compare_functor(M T::*mp) {
    return CompareMember<T, M> { mp };
}

Here's a demo.

Note that I added const to the pointer-to-member-function signatures, and corrected a couple of typos in the question's code.

Also make_compare_functor should probably be renamed to make_compare now that it accepts pointer-to-members as well.

Upvotes: 1

Related Questions