Custom class with overloaded operators causes C267

2019-09-09 03:02发布

问题:

i've got something strange here.

I have written a custom class HashedString:

class HashedString {
        protected:
            std::string str;
            long hash;

        public:
            HashedString(std::string str);
            ~HashedString();

            std::string GetString();
            long GetHash();

            bool operator== ( HashedString & o ) {
                return this->hash == o.GetHash();
            }
            bool operator<= ( HashedString & o ) {
                return this->hash <= o.GetHash();
            }
            bool operator>= ( HashedString & o ) {
                return this->hash >= o.GetHash();
            }
            bool operator< ( HashedString& o ) {
                return hash < o.GetHash();
            }
            bool operator> ( HashedString & o ) {
                return this->hash > o.GetHash();
            }
            bool operator!= ( HashedString & o ) {
                return this->hash != o.GetHash();
            }
            std::ostream& operator<<(std::ostream& lhs) {
                return lhs << "{" << hash << ": " << str << "}";
            }
    };


std::map<HashedString, Resource> resources;

When using it in a map as a key like above i get the following error:

binary operator '<' : no operator defined which takes a left-hand operand of type 'const HashedString' (or there is no acceptable conversion)

I am not able to get it work, furthermore i don't understand why this code is rejected by the compiler.

Does anybody know the solution and the mistake i have done here?

Thanks, Xeno

回答1:

You need to make your operator const. It should also take a const reference:

bool operator< (const HashedString& o ) const { .... }

Alternatively, you can make it a non-menber operator:

bool operator<(const HashedString& lhs, const HashedString& rhs)
{
  lhs.GetHash() < rhs.GetHash();
}

This would be the preferred option, since it is symmetrical for both operands.

Note that it doesn't make sense for a comparison operator to mutate either of its operands. This applies to all of your comparison operators.

Finally, for this to work, you will have to make GetHash() const too:

long GetHash() const;

Edit: I didn't go into this before, but clearly this mechanism is fragile against hash collisions. Unless you have perfect hashing in your range of key values, you may be better off using an std::unordered_map<std::string>.