Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why a non-member == operator overloading needed when using a std::pair as a std::unordered_map key

In the below example I have overloaded the conversion functions for uint8_t and bool. And used a pair as the map key with boost::hash.
There was a previous error ambiguity in conversion of 'const Mem' to 'float' (not sure why it’s requesting a Mem -> float conversion) so I decided to add an overloading for == operator. This will give an compile error in clang++ if I only implement the member operator overloading for the == operator.

In file included from /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/iostream:39:
In file included from /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/ostream:38:
In file included from /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/ios:40:
In file included from /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/char_traits.h:39:
In file included from /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/stl_algobase.h:64:
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/stl_pair.h:467:51: error: use of overloaded operator '==' is ambiguous (with operand types 'const Mem' and 'const Mem')
    { return __x.first == __y.first && __x.second == __y.second; }

Why do I need a non-member overload of == since __x and __y are same type and can be supported from member operator. Example run

#include <iostream>
#include <cstdint>
#include <unordered_map>
#include <string>

#include <boost/functional/hash.hpp>

struct Mem {
    bool inv : 1;
    uint8_t bit : 3;

    Mem(bool v = false, uint8_t bs = 0) : inv(v), bit(bs) {}

    operator uint8_t() const
    {
        return (bit << 1 | inv);
    }
    
    operator bool() const
    {
        return inv;
    }
    
    // not working for member overloading
    bool operator==(const Mem& other) 
    { 
        return inv == other.inv;
    }

};

// only work for non-member overload
// inline bool operator==(const Mem& lhs, const Mem& rhs) 
// { 
//     return lhs.inv == rhs.inv;
// }

inline std::size_t hash_value(const Mem& mem)
{
    return mem.bit;
}


int main()
{
    std::unordered_map<std::pair<std::string, Mem>, std::string, 
                       boost::hash<std::pair<std::string, Mem>>> map {};

    auto i = Mem();
    std::string k = "T";

    auto p = map.find({k, i});
     
    return 0;
}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Your member operator== needs to be declared as const (like your other member operators are), eg:

bool operator==(const Mem& other) const
                                   ^^

Without that, your member operator== is ignored when the left-hand operand of a == comparison is a const Mem object. Your non-member operator== can by used instead because its lhs parameter takes a const Mem& object reference, which accepts both non-const Mem and const Mem objects.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading