4

How I can specialize std::greater by using std::rel_ops? I have something like this

#include <utility>
#include <functional>

using namespace std::rel_ops;

struct MyStruct {
    int field;
    bool operator < (const MyStruct& rhs) const {
        return field < rhs.field;
    }
};

So I need to sort elements in descending order. How I can do it by using operator <, std::rel_ops and std::greater?

Null
  • 1,950
  • 9
  • 30
  • 33
AkhMa
  • 53
  • 5

3 Answers3

4

I'm assuming you tried to do something similar to

MyStruct ms[] = {{10}, {50}, {30}, {20}};
std::sort(std::begin(ms), std::end(ms), std::greater<MyStruct>{});

This fails to compile because no suitable operator> will be found. That's because std::greater relies upon ADL to find the operator overload, and ADL searches in associated namespaces. std::rel_ops is not an associated namespace for MyStruct. You can get everything to work by adding a using declaration to the same namespace as MyStruct so that the relevant operator> will be found.

using std::rel_ops::operator>;

Live demo

But this is ugly, and not a viable solution in general, so forget about std::rel_ops and use Boost.Operators as Barry suggests.

Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Why do you think its ugly? it does exactly what it should do. – Surt Oct 16 '15 at 19:00
  • @Surt It's a matter of opinion of course, but if you wanted the other equality operators as well, then you'd need 4 using declarations. With Boost.Operators, you simply derive from `boost::totally_ordered` (after defining an `operator==` also for your type). – Praetorian Oct 16 '15 at 19:05
  • Well I like your solution as it doesn't need 3rd party includes. – Surt Oct 16 '15 at 19:09
1

You'd have to do it this way:

std::vector<MyStruct> v{...};

std::sort(v.begin(), v.end(), [](const MyStruct& lhs, const MyStruct& rhs){
    using namespace std::rel_ops;
    return lhs > rhs;
});

Although std::rel_ops is pretty lame. It's easier to use boost::less_than_comparable, in which you just add the operators directly into MyStruct:

struct MyStruct 
    : boost::less_than_comparable<MyStruct> // <== adds operator>,
                                            //          operator>=, 
                                            //      and operator<=
{
    MyStruct(int i) : field(i) { }
    int field;

    bool operator<(const MyStruct& rhs) const {
        return field < rhs.field;
    }
};

And then you can sort it the obvious way:

std::sort(v.begin(), v.end(), std::greater<MyStruct>());
Barry
  • 286,269
  • 29
  • 621
  • 977
0

std::rel_ops generate the other comparisons from == and < so you first need to define at least <

bool operator<(const MyStruct & lhs, const MyStruct & rhs) {
    return lhs.field < rhs.field;
}

Now rel_ops generate > so now you can use std::greater in std::sort

std::sort(begin(myVector), end(myVector), std::greater<MyStruct>());
Surt
  • 15,501
  • 3
  • 23
  • 39
  • I have already defined operator < but I got error C2676 from std::greater – AkhMa Oct 16 '15 at 18:41
  • Your `<` has only one parameter, and `std::greater` demands two, further yours is a class member that is not accessible by `std::greater`. – Surt Oct 16 '15 at 18:46
  • There's no need to have non-member `operator<`, the member version the OP defined is sufficient. The problem lies with ADL not finding the `operator>` defined within `namespace rel_ops`. – Praetorian Oct 16 '15 at 18:59
  • @Praetorian, yes I can see that from your answer :) now I wonder why. – Surt Oct 16 '15 at 19:03