Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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.

share|improve this question
add comment

4 Answers

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

share|improve this answer
    
+1 That's excellent. I thought functions like std::mem_fn are useless... but this is insane. –  M M. 11 hours ago
    
@MM. I used to have this feeling too, but I realized I was confusing it with the old-fashioned std::bind_1st, std::binary_function etc. brand of functor composition. Not anymore! –  sehe 10 hours ago
1  
ok, that is a valuable alternative, but (@Ryan) please tell me why this should be better than a single-line lambda? –  davidhigh 10 hours ago
1  
It was meant like this (and I already corrected it before reading your suggestion)... I ask it here as I guess he was among the upvoters. –  davidhigh 10 hours ago
    
@davidhigh it's less redundant, it's more generic (can accept any functor, the sample also accepting mixed type parameters, leveraging potential implicit conversions). For me the leading reason would be to avoid errors (the expression f(a) < f(b) repeats both the f() application and the conceptual <) –  sehe 10 hours ago
show 4 more comments

A templated comparator could help you:

template <typename StructureType,
          typename MemberType,
          MemberType StructureType::*member>
bool comparator(const StructureType& the_first, const StructureType& the_second)
{
  return the_first.*member < the_second.*member;
}

http://ideone.com/K8ytav

A bit of type traits magic could certainly allows you to avoid writing the type.

share|improve this answer
add comment

How about once overloading operator< for your custom type? This can be naturally done inside the class (or directly next to it), and then no further argument is required beside the iterators.

Passing your val() function isn't possible, as you must pass a binary operator.

EDIT: Having read the other valuable alternatives (also sehe's nice response), I want to confirm what I already mentioned in the comment below: In my opinion, nothing beats the readibility, locality and also flexibility of a lambda expression (--on the risk of writing some passages twice).

@Ryan Haining: I suggest you to keep it as in your original post.

share|improve this answer
    
because it often doesn't make sense to say that something is less than another. if I want to sort employees by salary, that would mean overloading operator< to compare by salaries. this is not expressive because it's not intuitive to say one person is "less than" another, and because if I later need them sorted by age, I'm back to square one. –  Ryan Haining 11 hours ago
    
Then I guess the lambda is the shortest possibility you can expect. Of course you could also make somehow stack together std::bind with std::less, but this will be harder to read, imo. –  davidhigh 11 hours ago
add comment

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)));
share|improve this answer
    
Where less<> is a C++1y feature. –  dyp 8 hours ago
    
@dyp Works in VS2013, make it less<int> and it'll work in g++4.8 –  Nikos Athanasiou 8 hours ago
    
Yes, that's one of the (few) features MSVC supports "ahead of time", like make_unique. IIRC both have been proposed my Microsoft employees. –  dyp 8 hours ago
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.