11

hash<T>ユーザー定義のファンクターを定義する必要があるC++ 11標準からはわかりません。

たとえば、23.5.2 Header<unordered_map>では、次のように表示されます。

template <class Key,
        class T,
        class Hash = hash<Key>,
        class Pred = std::equal_to<Key>,
        class Alloc = std::allocator<std::pair<const Key, T> > >
    class unordered_map;

hash<T>これは、デフォルトでがグローバル名前空間で検索されるのに対し、equal_to<>は名前空間で検索されることを示唆していstdます。

hash<>との名前空間の違いはなぜequal_to<>ですか?

(実際、http://www.cplusplus.com/reference/unordered_map/unordered_map/stdの説明では、どちらも名前空間を指定していません。)

したがって、ユーザー型のファンクターを定義するとき、それをブロックhash<>内に囲む必要namespace std { }がありますか?それとも現在の名前空間に残すことができますか?

コードに が含まれていない場合、using namespace std;STL コンテナーは、プリミティブ型に関連付けられた事前定義されたファンクターを名前空間でunordered_map検索する方法を知っているのでしょうか? デフォルトではこれらが見つからないようです。stdhash<>Hash = hash<Key>

これらがばかげた質問である場合は申し訳ありません..

4

2 に答える 2

6

まず第一に、テンプレートには「引数依存のルックアップ」はありません。そのため、グローバル名前空間内またはグローバル名前空間内hash<Key>のいずれかで、常に同じテンプレートを参照します。異なる翻訳単位の異なるテンプレートに解決された場合、ODR 違反によって未定義の動作が発生します。これだけでも、here が を意味することを示唆しています。stdKeyhashstd::hashunordered_map

namespace std {
    template<class T> struct hash;

    template <class Key,
        class T,
        class Hash = hash<Key>,    // resolves to std::hash<Key> for all Keys
        class Pred = std::equal_to<Key>,
        class Alloc = std::allocator<std::pair<const Key, T> > >
    class unordered_map;
}

ただし、標準ヘッダーで宣言された型は、ソースに記述する必要はありません (原則として、コンパイラに組み込まれているか、他の魔法によってプリコンパイルされている可能性があります)。標準では、各標準ヘッダーがその概要で型のみを宣言する必要があります。つまり、std::hash宣言を省略することにより、標準では、上記の名前空間の汚染を回避するために、いくつかの仮想的な実装が許可されます。これは、概要に上記の宣言が表示されない理由を説明しています。

上記の結論をさらに裏付けるために、§20.8.12 クラス テンプレート ハッシュ [unord.hash] に進みます。

23.5 で定義された順序付けられていない連想コンテナは、クラス テンプレート ハッシュの特殊化をデフォルトのハッシュ関数として使用します。

この段落は を参照しておりstd::hash、 の概要から推測でき<functional>ます。

結論:これは、標準の書式設定の矛盾です。多くの不一致があるため、この特定のケースはまったく驚くべきことではありません。そのような場合、何が意図されているのかを理解するために、何が唯一の理に適ったものかを推測する必要があります。

専門化。テンプレートは、宣言された名前空間で特殊化します。独自のタイプの標準テンプレートを特殊化する権利が明示的に付与されます。

namespace std {
    template<> struct hash<YourClass> {
        // specialization goes here
    };
}
于 2013-02-03T07:31:23.367 に答える
-1

タイプのハッシュファンクターを定義したい場合は、それを名前空間に入れてインスタンスunordered_xxx化するだけです-非常に簡単です...

namespace my {
struct some_type {/*...*/};
struct some_hasher {/*...*/};
}

typedef std::unordered_map<int, my::some_type, my::some_hasher> my_some_hash_map;

私の知る限り、名前空間にsmthを追加することはお勧めできません(そして明らかに安全ではありません)std。実際には必要ありません(私の経験では、いつスマートに追加したいか思い出せませんstd-これを行わなくても「問題」を解決することは常に可能です)

そしてところで:

これは、デフォルトで hash がグローバル名前空間で検索され、equal_to<> が std 名前空間で検索されることを示唆しています。

違う!このことを考慮:

namespace my {
// See declaration of some_type above...
template <
    typename SomeType = some_type
  , typename Alloc = std::allocator<SomeType>
  >
struct test;
}

明らかにsome_type、現在の名前空間で検索されます!

したがって、ユーザー型の hash<> ファンクターを定義するとき、それをnamespace std { }ブロック内に囲む必要がありますか、それとも現在の名前空間に残すことができますか?

いいえ!テンプレートの特殊化を提供することで、シンボルの数をタイプに減らそうとしないstd::hash<YourType>でください -- 名前空間に独自のハッシュ ファンクターを記述し、インスタンス化時にテンプレート パラメーターとして追加するだけstd::unordered_xxxです ...

この単純なルールに従ってください:あなたの管理下にない(すべての名前空間! だけでなく...)に smth を追加することは避けてください。namespacestd

于 2013-02-03T07:31:33.780 に答える