61817


コメントアウト部(２箇所)に注意して、  
以下のコードをコンパイルすると、コンパイルエラーが出ます。

[code]

    #include <unordered_set>
    
    struct A{
        int x;
        bool operator==(const A& other) const {
            return x == other.x;
        }
        struct Hash{
            size_t operator()(const A& a) /*const*/{
                return std::hash<int>()(a.x);
            }
        };
    };
    
    int main(){
        std::unordered_set<A, A::Hash> set; // compile error
        return 0;
    }
    
[/code]

[code]

    error: no match for call to '(const A::Hash) (const A&)'
      noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
    
[/code]

このコンパイルエラーは一体どのように解釈すればよいのでしょうか。

どのようにして、メンバ関数がconstであるかそうでないかに基づいて、このようにエラーを出すことができるのでしょうか。


CC BY-SA 4.0
2019-12-26T16:05:18.327
61812
2020-01-23T03:17:37.327
37013
question
c++
呼び出し元は、メンバ関数がconstであることをどのようにして認識していますか？


> このコンパイルエラーは一体どのように解釈すればよいのでしょうか。

[C++標準ライブラリ要件](https://timsong-
cpp.github.io/cppwp/n4659/hash.requirements)では、ハッシュ関数オブジェクト`h`とキー`k`がconst修飾されていても式`h(k)`でハッシュ計算を行えることを要請しています。  
つまり、ハッシュ計算用のクラス`Hash`は`size_t Hash::operator()(const Key&)
const`演算子オーバーロードを提供すべきです。

* * *

> どのようにして、メンバ関数がconstであるかそうでないかに基づいて、このようにエラーを出すことができるのでしょうか。

例えばgcc 8.3.0の[libstdc++-v3](https://github.com/gcc-
mirror/gcc/blob/gcc-8_3_0-release/libstdc%2B%2B-v3/include/bits/hashtable.h#L195-L196)ライブラリ実装では、下記static_assert文を用いて静的検査を行っています。

[code]

    static_assert(__is_invocable<const _H1&, const _Key&>{},
         "hash function must be invocable with an argument of key type");
    
[/code]

条件式[`__is_invocable`](https://github.com/gcc-
mirror/gcc/blob/gcc-8_3_0-release/libstdc++-v3/include/std/type_traits#L2611-L2624)`<const
_H1&, const
_Key&>`を、`std::unordered_set<Value,Hash,Pred,Alloc>`のテンプレートパラメータに置き換えると`__is_invocable<const
Hash&, const Value&>`となり、以下の関数オブジェクト呼出しが有効であれば`std::true_type`型となります。

[code]

    const Hash h;
    const Key k;
    h(k);
    
[/code]


CC BY-SA 4.0
2019-12-27T02:00:49.657
61817
2020-01-23T03:17:37.327
2020-01-23T03:17:37.327
49
49
61812
answer