In C++, for the operator greater than or equal to (">="), is it enough to have the operators equal ("=") and greater (">") overloaded to have functionality for the greater than or equal to (">=")? Or do I need to overload the operator (">=") to have functionality for it?
4 Answers
operator >=
is not a combination of operator >
and operator =
. operator >=
is its own operator but you can implement it in terms of operator <
Typically you would have something like
inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ } inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);} inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ } inline bool operator> (const X& lhs, const X& rhs){return operator< (rhs,lhs);} inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);} inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}
From sbi's answer on What are the basic rules and idioms for operator overloading?

- 171,901
- 28
- 288
- 402
is it enough to have the operators equal ("=")
Equal operator in c++ is ==
OR do I need to overload the operator (">=") to have functionality for it?
It depends what you mean by functionality. If you mean that if you define operator==
and operator>
will compiler generate operator>=
automagically for you? No, it would not, you have to implement it using existing operators or not.

- 43,454
- 1
- 47
- 90
-
Thanks! I thought the compiler will automatically do that. – Vasi Marin Sep 06 '18 at 14:02
-
Now in C++20, will the compiler generate the >= automagically ? – 0xB00B Apr 17 '22 at 02:20
No, C++ does not write those operators for you.
If you think that sucks, you are right. A bunch of ways to make this suck less have been done. I'll talk about 4 of them.
Wait for c++20
In c++20, if you write operator<=>
(the 3-way "spaceship" operator) properly, or =default
it, then all of <
, <=
, >=
, >
, !=
and ==
will be written for you.
struct bob {
int x,y;
auto operator<=>( bob const& )const = default;
};
The above bob
has every <
==
etc operator written for it by C++ now.
Just write them
Prior to c++20 you have to write all of them if you want all of them. This is tedious and error-prone.
Using std::tie
and invoking <
and the like on them is slightly less error-prone:
struct bob {
int x, y;
friend bool operator<( bob const& lhs, bob const& rhs ) {
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
};
or even
struct bob {
int x, y;
friend auto as_tie( bob const& b ) { // C++14
return std::tie(b.x, b.y);
}
friend bool operator<( bob const& lhs, bob const& rhs ) {
return as_tie(lhs) < as_tie(rhs);
}
};
because tuple
does a proper lexographic comparison; writing lexographic comparions without bugs is annoying.
Metaprogram your way around it
When comparing strings you usually use strcmp
. This returns a negative number if less, a positive number if greater, and 0 if equal. This pattern can be more efficient than doing <
or ==
repeatedly.
Making a single strcmp
like function produce <
==
and the other comparison operations can be done:
namespace utils {
template<class D>
struct use_cmp {
friend bool operator<( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) < 0;
}
friend bool operator>( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) > 0;
}
friend bool operator<=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) <= 0;
}
friend bool operator>=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) >= 0;
}
friend bool operator==( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) == 0;
}
friend bool operator!=( use_cmp<D> const& lhs, use_cmp<D> const& rhs ) {
return cmp( lhs.self(), rhs.self() ) != 0;
}
private:
D const& self() const { return *static_cast<D const*>(this); }
};
}
Now supose we have a type:
struct bob {
int x, y;
};
and we want to be able to use comparison operators on it:
struct bob : utils::use_cmp<bob>
{
int x, y;
bob( int x_, int y_ ):x(x_), y(y_) {} // constructor
friend int cmp( bob const& lhs, bob const& rhs ) {
if (lhs.x < rhs.x) return -1;
if (lhs.x > rhs.x) return 1;
if (lhs.y < rhs.y) return -1;
if (lhs.y > rhs.y) return 1;
return 0;
}
};
and using the magic of CRTP bob
now has every comparison operator written for it.
That annoying friend int cmp
(which gets more annoying the more members you have in it) can be handled by yet more boilerplate helper code:
namespace utils {
template<class...Ts>
int cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs );
template<class T, class...LowPriority>
int cmp( T const& lhs, T const& rhs, LowPriority&&... );
template<class...Ts, std::size_t...Is>
int tuple_cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs, std::index_sequence<Is...> ) {
int result = 0;
( (result = cmp( std::get<Is>(lhs), std::get<Is>(rhs) )) && ... );
return result;
}
template<class...Ts>
int cmp( std::tuple<Ts...> const& lhs, std::tuple<Ts...> const& rhs ) {
return tuple_cmp( lhs, rhs, std::make_index_sequence<sizeof...(Ts)>{} );
}
template<class T, class...LowPriority>
int cmp( T const& lhs, T const& rhs, LowPriority&&... ) {
if (lhs < rhs) return -1;
if (rhs < lhs) return 1;
return 0;
}
}
which is yet more arcane code, but you get a simpler bob
:
struct bob : utils::use_cmp<bob>
{
int x, y;
bob( int x_, int y_ ):x(x_), y(y_) {}
friend auto as_tie(bob const& b) {
return std::tie(b.x,b.y);
}
friend int cmp( bob const& lhs, bob const& rhs ) {
return utils::cmp( as_tie(lhs), as_tie(rhs) );
}
};
Note, however, that all of this is done and better by operator<=>
in c++20.
Use someone else's solution
This is similar to the approach boost::operators uses to write these operators for you.

- 1
- 1

- 262,606
- 27
- 330
- 524
Using an obvious notation, ">
|| ==
" is actually an over-requirement for >=
.
Although note that for all the relational operators, you only actually need <
, since equivalence is established if a < b
and b < a
are both false. In fact this is one of the concepts used in ordered C++ standard library containers.

- 12,186
- 6
- 68
- 106

- 231,907
- 34
- 361
- 483
-
-
-
1
-
1oh sure, maybe "although" should be "because"? I guess thats what caused my confusion, otherwise it completely makes sense – 463035818_is_not_an_ai Sep 06 '18 at 14:10