问题
I have a struct with some members and I have an implemented operator== for it. Is it safe to implement the operator< with the help of operator==? I want to use this struct in a set, and I want to check that this struct is unique.
struct Data
{
std::string str1;
std::string str2;
std::string str3;
std::string str4;
bool operator==(const Data& rhs)
{
if (str1 == rhs.str1
&& str2 == rhs.str2
&& str3 == rhs.str3
&& str4 == rhs.str4
)
return true;
else
return false;
}
// Is this ok??
bool operator<(const Data& rhs)
{
return !this->operator==(rhs);
}
}
So when I insert this struct to a std::set what will happen?
回答1:
Nope, it's quite unsafe. The simplest way to implement it is through std::tie.
#include <tuple>
struct Data
{
std::string str1;
std::string str2;
std::string str3;
std::string str4;
bool operator<(const Data& rhs) const // you forgot a const
{
return
std::tie(str1, str2, str3, str4) <
std::tie(rhs.str1, rhs.str2, rhs.str3, rhs.str4);
}
}
回答2:
No, that is not safe. The way you've defined <, a < b and b < a will both be true at the same time.
So when I insert this struct to a std::set what will happen?
The behaviour is undefined, so anything is permitted, and it will likely be different on different implementations.
回答3:
Well your code suggests that if A!=B, that means that A<B which is definitely wrong, since it can as well be A>B.
You will have to implement your > and < operators the same way you did with the operator==, which means by comparing the objects member-wise. It's up to you to decide how to determine if A is "more" or "less" than B based on their members.
If you use the operator as you have it in any of the standard library containers, you will get UB.
回答4:
You need to define operator< in its own terms. You cannot implement operator< in terms of operator==, although you may be able to do the reverse.
Consider the paradox in this truth table:
"a" < "b" : TRUE
"b" < "a" : TRUE
If your implementation of operator< yields the above paradox, which it does if you implement it in terms of operator== then you have not correctly implemented strict weak ordering. What you've implemented is a jumbled mess.
You need to determine which of the member strings take precedence over the others, and then perform a comparison between them in order -- from most important to least important.
For example, if the precedence of the string is, from most important to least important:
str1str2str3str4
...then this yields the following algorithm for operator<:
bool operator<(const Data& rhs) const
{
if( str1 < rhs.str1 )
return true;
if( rhs.str1 < str1 )
return false;
if( str2 < rhs.str2 )
return true;
if( rhs.str2 < str2 )
return false;
if( str3 < rhs.str3 )
return true;
if( rhs.str3 < str3 )
return false;
if( str4 < rhs.str4 )
return true;
if( rhs.str4 < str4 )
return false;
return false;
}
Using this, you could optionally next re-implement operator== in terms of operator<. You assume the inherent inefficiency of time complexity in doing so, however:
bool operator==(const Data& rhs) const
{
return !operator<(rhs) && !rhs.operator<(*this);
}
来源:https://stackoverflow.com/questions/12782225/is-it-safe-to-use-operator-as-operator-in-a-stdset