6

If I already have operator > and operator < defined (and operator ==), do I need to define operator >= and operator <=, or will the compiler declare them for me if I intentionally don't declare them?

Also, if I have operator == defined, will the compiler declare operator != for me?

Jamin Grey
  • 10,151
  • 6
  • 39
  • 52
  • 2
    If you have `operator<` and `operator==` defined, you could drag in the [`std::rel_ops`](http://en.cppreference.com/w/cpp/utility/rel_ops/operator_cmp) namespace to provide the rest of the operators, but this is not really a [good solution](http://stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops). [Boost.Operators](http://stackoverflow.com/a/14756785/241631) is the right way to do this. – Praetorian Jul 23 '13 at 18:02
  • Something just doesn't sit right with me using inheritance to save typing a few operators. Would rather add them manually. =) – Jamin Grey Jul 23 '13 at 18:09
  • deriving from a class that provides the functionality also has great documentation value. It is a primitive form of Concepts. – TemplateRex Jul 23 '13 at 19:31

3 Answers3

6

No, the Compiler won't declare/define any of the operators you did not define manually. However, Boost.Operators might be to your liking - it does exactly what you want the compiler to do.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • Dang. They generate decent default copy-constructors and such. Was hoping for a simple auto-generated *operator!=(other) { return !(*this == other); }*. Oh well, thanks for the answer! Will wait a bit before accepting it. – Jamin Grey Jul 23 '13 at 18:00
  • 1
    +1 the maintainer of Boost.Operators (Daniel Frey) has an uofficial port called [df.operators](https://github.com/d-frey/operators) of that library to C++11 (rvalue overloads and noexcept) – TemplateRex Jul 23 '13 at 19:26
5

The compiler won't do anything itself for you here, but it's relatively simple to generate automatically by inheriting from an appropriate class, something like:

template< typename DerivedType >
class ComparisonOperators
{
public:

    friend bool         operator!=( 
                            DerivedType const&  lhs,
                            DerivedType const&  rhs )
    {
        return !(lhs  == rhs);
    }

    friend bool         operator<=( 
                            DerivedType const&  lhs,
                            DerivedType const&  rhs )
    {
        return !(rhs < lhs);
    }

    friend bool         operator>( 
                            DerivedType const&  lhs,
                            DerivedType const&  rhs )
    {
        return rhs < lhs;
    }

    friend bool         operator>=( 
                            DerivedType const&  lhs,
                            DerivedType const&  rhs )
    {
        return !(lhs < rhs);
    }

protected:
                        ~ComparisonOperators() {}
} ;

Define < and == in your class, and derive from this, and you'll get all of the operators:

class MyClass : public ComparisonOperators<MyClass>
{
    //  ...
public:
    bool operator==( MyClass const& other ) const;
    bool operator<( MyClass const& other ) const;
    //  ...
};

Just a note: I've manually simplified the version I actual use, which defines == and < as well, looks for the member functions compare and isEqual, and uses compare for == and != when there is no isEqual. I don't think I've introduced any errors, but you never know.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • I tend to prefer a `int compare(DerivedType const &o)` which returns a negative, positive, or 0 value (traditional C approach). Usually `==` and `<` are very similar code so it's nice to merge them. – edA-qa mort-ora-y Jul 23 '13 at 18:27
  • 3
    Isn't that exactly what Boost.Operators already does for you? ;-) – Arne Mertz Jul 23 '13 at 18:49
  • @edA-qamort-ora-y Yes. That's the signature for `compare`, above. The rule is: only comparisons for equality: `isEqual` (and the relational operators will fail to compile if they're used); equality and relational, use `compare`; _if_ equality can be done much faster, then you can provide both. And there's a bit of meta programming in the `ComparisonOperators` class which will call the right one. – James Kanze Jul 24 '13 at 08:55
  • For the version I posted, yes; for the version I actually use, no. But I was unaware of the existance of Boost operators; my actual class pre-dates Boost, and does something more. (My solution also works with just one class: you don't have to distinguish between `less_than_comparable` and `equality_comparable`. I don't know whether that is an advantage or a disadvantage.) – James Kanze Jul 24 '13 at 09:01
0

There are already some good answers here using boost and inheritance. But as someone noted - using inheritance for operator creation seems... wrong.

I know #defines are "taboo" in C++, but still that's what I use here.

I have a #define in my general utility include that goes like this:

#define CREATE_COMPARITORS(name)                              \
inline bool operator>(const name &o){return o<*this;}         \
inline bool operator<=(const name &o){return not (o<*this);}  \
inline bool operator>=(const name &o){return not (*this<o);}  \
inline bool operator!=(const name &o){return not (*this==o);}

Then if I have a class, all I need to declare is operator< and operator==:

class ttt{
  //...
  bool operator<(const ttt &o);
  bool operator==(const ttt &o);
  CREATE_COMPARITORS(ttt);
  //...
};
rabensky
  • 2,864
  • 13
  • 18
  • You might need to justify that "seems... wrong." As of now I trust the boost library designers more than your unjustified opinion. – djechlin Jul 23 '13 at 19:30
  • Was quoting someone else in this thread who said "Something just doesn't sit right with me using inheritance to save typing a few operators". Now, if you want to downvote me because my answer was unhelpful or didn't add anything then fine. But if you downvote me just because I am one of a large group of people who don't like `Boost` and how it does things, while you happen to be part of another group who do like `Boost`, then you're abusing your power. – rabensky Jul 23 '13 at 19:54
  • -1 for recommending using #define over inheritance, with no justification for what's wrong with inheritance or why this code is exempt from the usual problems with macros. – djechlin Jul 23 '13 at 19:57
  • Boost does all kinds of things that are abusive of the language, to implement *features* that aren't already present, as a testbed for the features later getting standardized. Boost is very well designed, but sometimes has to use hacks to get code working because of the language limitations. Whether inheriting functionality is wrong or not isn't a big issue, but saying, 'Boost does it, so it must be a good practice' isn't necessarily true. I like Boost alot! The people who design it are very intelligent and better programmers than I. But that doesn't make it good practice. – Jamin Grey Jul 23 '13 at 19:57
  • Oh, also, [boost uses macroes](http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html) too. Since Boost uses it, they must be good! =P *deliberately tongue in cheek jab at @djechlin* (just to try to lighten the mood, not actually advocating, or bashing, the use of macroes). Not intentionally bashing djechlin either. =) – Jamin Grey Jul 23 '13 at 20:00
  • @JaminGrey that's a good point regarding Boost's conscientious use of abuse of language features I hadn't considered. Downvote otherwise stands. – djechlin Jul 23 '13 at 20:16