既知の理由で(具体的には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;
}
@Downvoter私の質問を改善し、何が間違っているのか教えてください... –
btw、あなた** **特化 'std :: hash' – bolov
@bolov私は変更できませんでした - >は許されず、禁止されている - >仕様書が未定義の動作を引き起こす可能性があるので、推奨されません。 –