You cannot guarantee, given only an implementation of operator<
, that a == b
.
This is because there exists a concept called "Partial Ordering", which may, under unusual circumstances, permit a scenario where two objects can be conditionally ordered against each other.
Consider, as an example, a graph describing class inheritance. We could define the following rules:
- Class
A
is equal to Class B
if A
and B
describe the same class.
- Class
A
is greater than Class B
if A
is a superclass of B
or is a superclass of a superclass of B
or so on (B
inherits from A
, or B
inherits from C
which inherits from A
, etc.)
- Class
A
is less than Class B
if A
is a subclass of B
(A
inherits from B
, or A
inherits from C
which inherits from B
, etc.)
- Class
A
is not ordered with respect to Class B
if they have no relation to each other (A
does not inherit from B
, and B
does not inherit from A
)
- Class
A
is not ordered with respect to Class B
if they both inherit from the same superclass, but otherwise have no relation (A
inherits from C
, B
inherits from C
)
- Class
A
is not ordered with respect to Class B
if they are mutually inherited from the same subclass, but otherwise have no relation (C
inherits from both A
and B
)
This makes it fully plausible that, given the following function:
std::string compare(T const& a, T const& b) {
if(a == b)
return "Equal to";
else if(a < b)
return "Less than";
else if(a <= b)
return "Less than or Equal to";
else if(a > b)
return "Greater than";
else if(a >= b)
return "Greater than or Equal to";
else
return "Unordered to";
}
The output could be "Unordered to"
, given some inputs.
The only way to guarantee that two generic arguments are equal to each other is to have an overload for operator==
.
Now, the good news for you is that if you're constructing a Binary Search Tree, there's an unwritten convention that the types being used to compare against should be, at the very least, weakly ordered (which means a==b
will return the same as !(a < b || b < a)
). So in your specific circumstances, so long as the provided key value is weakly ordered, !(a < b || b < a)
will always return true when the objects are equal.
But you do need some mechanism to ensure the user doesn't try to pass a partially ordered key to your comparison function. Otherwise, you're stuck requiring a full operator==
implementation.
P.S: Before someone jumps in and says "What about arithmetic types?", I would remind you that NaN
exists for IEEE-compliant Floating point values, where a < b
and b < a
can both return false. a == b
can also return false if both a
and b
are NaN
, even if both NaN
values have the same payload! Additionally, this relationship is only guaranteed for integers in a twos-compliment representation, which the C++ standard does not require.