Consider the following code:
#include <iostream>
#include <map>
#include <utility>
struct Key{
    int attr1, attr2;
    Key(int attr1, int attr2) : attr1(attr1), attr2(attr2) {}
    friend bool operator== (const Key& s1, const Key& s2);
    friend bool operator< (const Key& s1, const Key& s2);
};
bool operator== (const Key& s1, const Key& s2){
    return ((s1.attr1 == s2.attr1) && (s1.attr2 == s2.attr2));
}
bool operator< (const Key& s1, const Key& s2){
    return (s1.attr1 < s2.attr1);
}
int main(void){
    std::map<Key, int> mmap;
    mmap.insert(std::make_pair(Key(10, 10), 5));
    mmap.insert(std::make_pair(Key(10, 20), 5));
    std::cout << mmap.size() << std::endl;
}
The output is 1 where I would expect it to be 2. This seems to be due to only attr1 being compared in the operator<. However if I am correct, the comparison does not have to be a strong ordering, but rather having a weak ordering is sufficient. Is there some other bug here or do I have to define an operator< for which
Key1 !< Key2 && Key2 !< Key1implies thatKey1 == Key2
holds true?
                        
std::mapdoes not useoperartor ==at all when comparing elements. By default, and in this case, it usesstd::lesswhich uses youroperator <. Since youroperator <only comparesattr1, and both objects have the sameattr1, the are considered equivalent and thus you only have one object in the map.To fix this you need to check both members and you can use the
std::tietrick to make a tuple that does this for you likeAnother option is to use a
std::unordered_mapwhich uses a hashing algorithm and an equality operator. Using that you can hashattr1only, but have the equality operator check bothattr1andattr2to make sure a true duplicate is not added.