I often find myself using std::sort
, std::max_element
, and the like with a lambda that simply invokes a member function
std::vector<MyType> vec;
// populate...
auto m = std::max_element(std::begin(vec), std::end(vec),
[](const MyType& a, const MyType& b) { return a.val() < b.val()})
this feels like a waste of characters and a loss of clarity. I'm aware that I could write another function/callable and pass a function pointer/callable object to these algorithm functions, but I often need to do this sort-by just once in a program and it doesn't strike me as a good way of addressing the problem. What I want to do, ideally is say:
auto m = std::max_element(std::begin(vec), std::end(vec), &MyType::val);
and have the objects be sorted by their val()
s. Is there some part of the stdlib I'm overlooking that could assist me with this? or another simple way of doing it? I'd like to make what this is sorting or searching by as obvious as possible.
I'm aware that just &MyType::val
isn't enough, I am looking for something that could perhaps wrap it, or provide a similar functionality without obscurring the meaning.
You can use std::mem_fn
(or std::tr1::mem_fn
)
int main()
{
std::vector<MyType> vec;
auto m = std::max_element(std::begin(vec), std::end(vec), compare_by(std::mem_fn(&MyType::field)));
}
Of course, this assumes that you have a utility like compare_by
in your toolbox (as you should :)):
template <typename F>
struct CompareBy {
explicit CompareBy(F&& f) : f(std::forward<F>(f)) {}
template <typename U, typename V>
bool operator()(U const& u, V const& v) const {
return f(u) < f(v);
}
private:
F f;
};
template <typename F>
CompareBy<F> compare_by(F&& f) { return CompareBy<F>(std::forward<F>(f)); }
See it Live On Coliru
You can do it without introducing any new functions (templated or not).
Just use bind
and std::less
auto m = std::max_element(vec.begin(), vec.end(),
bind(less<>(), bind(&MyType::val, _1), bind(&MyType::val, _2)));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With