Reputation: 5256
During a code review a colleage from mine was sorting a std::set using a struct. I am still quite new in C++ and had to implement it myself to fully understand it. Sadly I had some struggle because the MSVC forced me to implement operator< too after I implemented operator() of the struct.
Can someone explain me why it is necessary to implement both operator if I use a struct for sorting a std::set? I guessed that operator< is not needed because std::set calls some basic compare function?
class Hallo {
int one;
int two;
public:
Hallo(int one, int two);
bool operator < (const Hallo& rhs) const
{
return one < rhs.GetOne();
}
struct cmpStruct{
bool operator()(Hallo const &lhs, Hallo const &rhs) const
{
return lhs.GetOne() < rhs.GetOne();
}
int main(int ac, char* av[]){
const Hallo a{ 1, 1 };
const Hallo b{ 2, 2 };
const Hallo c{ 3, 3 };
const Hallo d{ 5, 5 };
std::set<Hallo, Hallo::cmpStruct> sortedList{};
std::set<Hallo> unsortedList{};
sortedList.insert(b);
sortedList.insert(c);
sortedList.insert(a);
sortedList.insert(d);
unsortedList.insert(b);
unsortedList.insert(c);
unsortedList.insert(a);
unsortedList.insert(d);
Upvotes: 3
Views: 877
Reputation: 44238
Can someone explain me why it is necessary to implement both operator if I use a struct for sorting a std::set?
Because you created 2 instances of std::set
with class Hallo
as a key and in the first you explicitly used cmpStruct
as a functor, but in the second you implicitly use std::less
as stated in documentation
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
and std::less
uses "some basic compare function" which is operator<
documentation:
Function object for performing comparisons. Unless specialized, invokes operator< on type T.
emphasis is mine. So unless you specialize std::less
for class Hallo
or would not replace std::less
in std::set
instantiation with something else it would require operator<
either as method or standalone function.
Upvotes: 3
Reputation: 7837
The members of any mathematical set are unique; no two can have the same key. But what does the same mean for a user-defined type like struct
? We know what it means for two strings to be equal, or two integers. But the meaning of "same" for your struct is up to you, and up to you to define.
The members of std::set
are both unique and sorted, by definition. So, beyond enforcing uniqueness, std::set
represents the members in order. What order? Again, for user-defined types, it's up to the user to define what it means for one object to be "less than" another.
That's where operator<
comes in. You define what it means for one of your objects to be less than the other. std::set
calls your user-defined operator on your user-defined type, and puts the members in the order thus defined. It also uses that function to enforce uniqueness: If a new item cannot be inserted before an existing one nor after it, it's equal to it, and the insertion is rejected.
Upvotes: 0
Reputation: 57678
By default, std::set
uses operator <
to compare two Hallo
instances. This is why you would need to define an operator<
function for comparing them. There is no default operation for comparing struct
s.
Edit 1: Specifying an ordering or comparison function
One of the std::set
constructors allows you to specify a function for comparing Hallo
instances. If you don't want to add an overloaded operator<
method to your struct, you'll need to pass a function that compares two Hallo
instances, to the std::set
constructor. Again, there are no default comparison operators for struct
or class
instances; you'll have to create something.
Edit 2: Purpose of comparison function
The comparison function argument of std::set
allows you specify a comparison function for your Hallo
structure. It allows you to create one set that orders by member one
and you could create another set that orders by the two
member.
Also, you can define the ordering function for ascending or descending orders. The choices are plentify.
Upvotes: 2