3

Let's say I have

struct Value { int foo(); };
size_t *begin = ...,
       *end   = ...;

If I want to sort a bunch of Value indices in C++03, I have to write something tedious like this:

struct Comparator
{
    Value *data;
    Comparator(Value *data) : data(data) { }
    bool operator()(size_t a, size_t b)
    { return data[a].foo() < data[b].foo(); }
};
sort(begin, end, Comparator(data));

Is there any way to write this more neatly, preferably in 1 line, with Boost (perhaps with Boost.Lambda)?

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Your example code doesn't make sense. Comparator's `operator()` takes `size_t`, while `begin/end` are `Value*`s. That's not going to compile. – Nicol Bolas Jul 21 '12 at 05:40
  • @NicolBolas, Luc Danton: My bad, those were supposed to be indices. I think it should be fixed now. – user541686 Jul 21 '12 at 05:42
  • 2
    @Mehrdad: Then you're not sorting a "bunch of `Value`s" anymore; you're sorting a bunch of *indices* into a `Value` array. – Nicol Bolas Jul 21 '12 at 05:45
  • @NicolBolas: I guess so. I'm sorting a 'view' of them... I don't think that changes the essence of my question though. – user541686 Jul 21 '12 at 05:47

2 Answers2

6

No.

Boost.Lambda works best when dealing with overloaded operators. Once you bring a named function call into things, Boost.Lambda becomes much less useful in making code more concise and easy to read. You have to start using function binders and other such things.

And the fact that you're using the lambda parameters as indices (rather than the values being indexed) probably screws things up as far as using operator[] in the Boost.Lambda library too.

You could make a Boost.Lambda equivalent of this. But it wouldn't be anything I would call "neat", and the "1 line" would be extremely long.

There's a reason why C++11 introduced lambdas into the language instead of just incorporating Boost.Lambda into the standard library.

Oh, and don't forget: Boost.Lambda is generally considered obsolete. Use Boost.Phoenix instead. Granted, it's not going to help you any more than Lambda does.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
3

Using Boost.Phoenix (which is the preferred lambda library of Boost):

#include <boost/phoenix/phoenix.hpp>

{
    // for bind and ref
    using namespace boost::phoenix;

    using namespace boost::phoenix::placeholders;
    std::sort(begin, end
              , bind(&Value::foo, ref(data)[arg1]) < bind(&Value::foo, ref(data)[arg2]) );
}

An alternative is to use LocalFunction which essentially lets you do what you're doing (passing a local type to std::sort, which is not allowed for C++03) in a portable fashion. Usage should be (code is untested for this one though):

#include <boost/local_function.hpp>

{
    int BOOST_LOCAL_FUNCTION(const bind& data, std::size_t lhs, std::size_t rhs)
    {
        return data[lhs].foo() < data[rhs].foo();
    } BOOST_LOCAL_FUNCTION_NAME(comparator)

    std::sort(begin, end, comparator);
}
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Wow, I just saw something amazing: Using `bind` instead of writing a C++11 lambda *for just 5 places* that use `stable_sort` reduced the binary size from 280 KB to 260 KB! I never thought that would happen... Awesome! – user541686 Jul 21 '12 at 07:24