0

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;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139

1 Answers1

1

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks, on separate scenario if I do ```if (Mem() == false)``` I'm getting ```error: use of overloaded operator '==' is ambiguous (with operand types 'Mem' and 'bool')```, do I need custom operators like ```bool operator!=(const bool other)``` or is there a way to avoid these ambiguities while keeping the ```bool()``` and ```uint8_t()``` ops – Nalaka Rajamanthri May 01 '23 at 18:28
  • 1
    @NalakaRajamanthri -- Well, you have stepped into the quagmire that overloaded operators will bring. And that is compiler errors such as this, and if not errors, the program calling functions you didn't expect to be called. – PaulMcKenzie May 01 '23 at 18:33
  • 1
    @NalakaRajamanthri both of your `operator==`'s compare only `Mem` objects, so `if (Mem() == false)` has to *either*: 1) convert the left-hand `Mem` object to a `bool` (via `operator bool()`), or 2) convert the right-hand `bool` to a `Mem` object (via `Mem(bool)` constructor). `Mem` supports both ways, so the compiler doesn't know which one to use, hence the ambiguity. You can mark your `Mem(bool)` constructor as [`explicit`](https://en.cppreference.com/w/cpp/language/explicit) (you should *usually* do that for any constructor that can be called with a *single* value that is not the class type) – Remy Lebeau May 01 '23 at 18:55