为什么 clang 拒绝 gcc 接受的 unordered_set 定义?

Why does clang reject this unordered_set definition gcc accepts?

我想用我自己的哈希函数测试 unordered_set:

#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;
}

我尝试编译它,但 clang 给出了大量错误:

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);
        ^

我不太明白这里的错误信息,你能帮忙告诉我如何修复我的代码吗?

您的比较运算符必须 const 合格:

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

通过将运算符实现为非成员函数,很容易避免此类错误。有关详细信息和最佳做法,请参阅 What are the basic rules and idioms for operator overloading?

虽然 Baum mit Augen 已经告诉您问题所在,但我认为最好也解释一下如何从错误消息中找出更多信息。

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);
        ^

第一部分告诉您将 const node 与另一个 const node 进行比较时出错。在这一点上,您将需要运用自己的判断力来确定您是否 应该 能够比较两个 const node

这里的答案是肯定的。此时您可以简化您的代码以将 unordered_set 排除在等式之外,并让编译器为您提供有关该问题的更多信息:

#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;
}

如果您尝试编译它,clang 会为您提供更多详细信息:

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" 告诉你到底是什么问题。要修复它,就像 Baum mit Augen 的回答一样,标记方法 const.

另一方面,如果答案是 "no, you are not supposed to be able to compare two const node objects",那么问题就是 "why is unordered_set comparing two const node objects and how can I stop it"。为此,初始编译器消息的其余部分将告诉您哪些部分导致了该比较。你必须从上到下,在每一步都弄清楚 "is this supposed to work?" 如果是,弄清楚为什么它不起作用。如果不是,找出导致尝试的原因。