Hind Forsum
Hind Forsum

Reputation: 10507

Why does clang reject this unordered_set definition gcc accepts?

I wish to test unordered_set with my own hash function:

#include<unordered_set>
#include<iostream>
#include<functional>
using namespace std;
struct node{
    size_t value;
    bool operator == (const node& n){return value == n.value;}
};
size_t h(const node& n){
    return n.value;
}
int main(){
    unordered_set<node, std::function<size_t(const node&)>> s2(3,h);//failed
    return 0;
}

I tried to compile it, while clang gives a huge amount of errors:

clang++ m.cpp -std=c++11
In file included from m.cpp:1:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/unordered_set:324:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:659:21: error: invalid operands to binary
    expression ('const node' and 'const node')
        {return __x == __y;}
                ~~~ ^  ~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__hash_table:2175:32: note: in instantiation of member
    function 'std::__1::equal_to<node>::operator()' requested here
                            key_eq()(__cp->__value_, __np->__next_->__value_);
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__hash_table:2121:9: note: in instantiation of member function
    'std::__1::__hash_table<node, std::__1::function<unsigned long (const node &)>, std::__1::equal_to<node>, std::__1::allocator<node> >::__rehash' requested here
        __rehash(__n);
        ^

I don't quite get the error information here, would you help to tell how I fix my code?

Upvotes: 4

Views: 586

Answers (2)

user743382
user743382

Reputation:

Although Baum mit Augen already told you the problem, I think it is a good idea to also explain how you could figure out more from the error message.

clang++ m.cpp -std=c++11
In file included from m.cpp:1:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/unordered_set:324:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:659:21: error: invalid operands to binary
    expression ('const node' and 'const node')
        {return __x == __y;}
                ~~~ ^  ~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__hash_table:2175:32: note: in instantiation of member
    function 'std::__1::equal_to::operator()' requested here
                            key_eq()(__cp->__value_, __np->__next_->__value_);
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__hash_table:2121:9: note: in instantiation of member function
    'std::__1::__hash_table, std::__1::equal_to, std::__1::allocator >::__rehash' requested here
        __rehash(__n);
        ^

This first part is telling you that there is an error comparing a const node to another const node. At this point, you will need to exercise your own judgement to determine whether you should be able to compare two const nodes.

The answer here is yes. At which point you can simplify your code to take unordered_set out of the equation, and get the compiler to give you more information about the problem:

#include<cstddef>
using namespace std;
struct node{
    size_t value;
    bool operator == (const node& n){return value == n.value;}
};
int main(){
    const node a{}, b{};
    a == b;
}

If you try to compile this, clang will give you more details:

error: invalid operands to binary expression ('const node' and 'const node')
        a == b;
        ~ ^  ~
note: candidate function not viable: 'this' argument has type 'const node', but method is not marked const
        bool operator == (const node& n){return value == n.value;}
             ^

"method is not marked const" tells you exactly what the problem is. To fix it, as in Baum mit Augen's answer, mark the method const.

If, on the other hand, the answer would have been "no, you are not supposed to be able to compare two const node objects", then the question would be "why is unordered_set comparing two const node objects and how can I stop it". For that, the rest of the initial compiler message will tell you what parts are causing that comparison. You would have to go from top to bottom, figuring out at each step "is this supposed to work?" If it is, figure out why it is not working. If it is not, figure out what is causing the attempt.

Upvotes: 8

Baum mit Augen
Baum mit Augen

Reputation: 50053

Your comparison operator must be const qualified:

bool operator == (const node& n) const {return value == n.value;}
                                 ^^^^^

Mistakes like this are easy to avoid by implementing the operator as a non-member function. See What are the basic rules and idioms for operator overloading? for more information and best practices.

Upvotes: 5

Related Questions