2016-06-01 6 views
1

既知の理由で(具体的にはhereなど)、std名前空間をカスタマイズしないでください。この原因は、という特殊化によってユーザー定義型に対してのみハッシュを再定義する最小限のアプローチを使用することをお勧めしません。std名前空間のすべての変更が未定義の動作をもたらす可能性があります。そのため、カスタムキーで順序付けられていないコレクションを使用する有効な方法は、独自のハッシュヘルパー構造体を作成してコレクションに渡すことだけです。コレクションの種類にアクセスするたびにそれを渡すことは、私の意見ではやや不便です。一方、C++ 11にはテンプレート化された型のエイリアシングを実行するためのtemplatedの構文が付属しています。私は、そのアプローチを使用することを奨励している順序付けられていないコレクションについてのstackoverflowに関する回答は見ていません。テンプレート化されたパラメータのカスタムデフォルト値を作成するためにテンプレート化を採用することには欠点がありますか? std名前空間からクラスのテンプレート化パラメータの既存のデフォルト値を新しく/変更するという一般的な問題をカバーするより良いパターンはありますか? std::tupleのハッシュ適用例:まず欠点は議論の余地あるテンプレートを使用して、unordered_map /カスタムキーを使用して適切なパターンを作成します。

- 私はちょうど私のためにこのようなコードが理解/読みやすくなり、「生」のSTDタイプを使用したい:

#include <tuple> 
#include <utility> 
#include <unordered_map> 

template <class T> 
struct my_hash: std::hash<T> { }; 

template < 
    class Key, 
    class T, 
    class Hash = my_hash<Key>, 
    class KeyEqual = std::equal_to<Key>, 
    class Allocator = std::allocator< std::pair<const Key, T> > > 
using my_unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator>; 

template <class...> 
struct integral_sequence { }; 

template <int Start, int End, class = integral_sequence<>> 
struct make_integral_sequence_impl; 

template <int Start, int End, class... Integrals> 
struct make_integral_sequence_impl<Start, End, integral_sequence<Integrals...> >: make_integral_sequence_impl<Start+1, End, integral_sequence<Integrals..., std::integral_constant<int, Start>>> { }; 

template <int StartAndBegin, class... Integrals> 
struct make_integral_sequence_impl<StartAndBegin, StartAndBegin, integral_sequence<Integrals...>>{ 
    using type = integral_sequence<Integrals..., std::integral_constant<int, StartAndBegin>>; 
}; 

template <int Start, int End> 
using make_integral_sequence = typename make_integral_sequence_impl<Start, End>::type; 

template <class Tuple> 
struct sizer; 

template <class... Args> 
struct sizer<std::tuple<Args...>> { 
    static constexpr size_t value = sizeof...(Args); 
}; 

template <class Tuple, class Indices = make_integral_sequence<1, sizer<Tuple>::value - 1 > > 
struct tuple_tail_impl; 

template <class Head, class... Tail, class... Indices> 
struct tuple_tail_impl<std::tuple<Head, Tail...>, integral_sequence<Indices...>> { 
    using type = std::tuple<Tail...>; 
    std::tuple<Head, Tail...> tuple; 
    std::tuple<Tail...> get() { 
     std::tuple<Tail...> result { std::get<Indices::value>(tuple)... }; 
     return result; 
    } 
}; 

template <class Tuple> 
typename tuple_tail_impl<Tuple>::type tuple_tail(const Tuple &t) { 
    tuple_tail_impl<Tuple> tti { t }; 
    return tti.get(); 
} 

template <class First, class... Other> 
struct my_hash<std::tuple<First, Other...>> { 
    std::size_t operator()(const std::tuple<First, Other...>& val) const { 
     return 805306457 * my_hash<std::tuple<Other...>>()(tuple_tail(val)) + my_hash<First>()(std::get<0>(val)); 
    } 
}; 

template <class First> 
struct my_hash<std::tuple<First>> { 
    std::size_t operator()(const std::tuple<First>& val) const { 
     return my_hash<First>()(std::get<0>(val)); 
    } 
}; 


int main() { 
    my_unordered_map<std::tuple<int, int>, int> mum; 
    mum[std::make_tuple(1, 2)] = 10; 
    mum[std::make_tuple(2, 3)] = 20; 
} 
+0

@Downvoter私の質問を改善し、何が間違っているのか教えてください... –

+0

btw、あなた** **特化 'std :: hash' – bolov

+0

@bolov私は変更できませんでした - >は許されず、禁止されている - >仕様書が未定義の動作を引き起こす可能性があるので、推奨されません。 –

答えて

1

を私は2つの欠点を参照してください:

using mkey = std::tuple<int, int>; 
std::unordered_map<mkey, int, my_hash<my_key>> mum; 

第二は、C++標準のいくつかの新しいバージョンは、他のデフォルトを持っているかもしれないということである - ので、あなたのプロジェクトがないのトラブルになり、新しいC++ STAに確認されていますどんなタイプでも、デフォルトのコンパレータをstd::equal_to<>に変更し、アロケータのパラメータタイプをpairからtupleに変更することは容易に想像することができます(このパラメータはそれほど重要ではないと表現しています)。std::allocator<>アロケータにタイプ...

+0

前方互換性の良い点!しかし、最初の欠点について - それぞれの可能な 'std :: unordered_map'のエイリアスを作成することは、' std :: tuple'のようなvariadicsに関しては特にスケーラブルではありません... –

+0

デフォルトのパラメータ値を:class KeyEqual = std :: unordered_map :: key_equal'と 'class Allocator = std :: unordered_map :: allocator_type'?将来の可能性のある標準をそれほど損なうことはないと思いますか? –

+0

はい、それは良いでしょう。しかし、たぶん私は自分の投稿の冒頭で言わなければならないかもしれません - これらは非常に小さな欠点です - 元のコードは悪くない、それは受け入れられる... – PiotrNycz

関連する問題