From f00450a06cd82463479b76a4242723b7cb28cb4a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 17 Aug 2014 03:23:35 +0200 Subject: [PATCH] ..and use this trait to build an automatic bridge from boost::hash to std::hash this completes the exploration; we should now be able to use any type with boost hash support in the std unordered containers without much ado. I wasn't able to come up with a completely modular solution, since the std::hash template has only one template parameter, which defeats using enable_if. But since we're controling the default implementation after the Hijacking anyway, we can as well go ahead directly to forward to an existing boost::hash function --- research/try.cpp | 103 ++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 5939c4f08..e0d59a941 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -45,16 +45,65 @@ ** we'll use the dirty trick proposed by "enobayram" to hijack and fix the problematic ** definition from the standard library. ** http://stackoverflow.com/questions/12753997/check-if-type-is-hashable + ** + ** Moreover, in this exploration, we build an automatic bridge to invoke + ** existing boost hash functions whenever a \c std::hash definition is required. ** */ #include +namespace lib { +namespace meta { + + namespace { + struct NoUsableHashDefinition { size_t more_than_one[2]; }; + typedef size_t HasUsableHashDefinition; + + NoUsableHashDefinition hash_value(...); + + } + + template + class provides_BoostHashFunction + { + TY const& unusedDummy = *(TY*)nullptr; + + public: + enum{ value = (sizeof(HasUsableHashDefinition) == sizeof(hash_value(unusedDummy))) }; + }; + +}} + +#include + namespace std { template struct __hash_base; + + template + struct _HashImplementationSelector + : public __hash_base + { + static_assert (sizeof(TY) < 0, "No hash implementation found. Either specialise std::hash or provide a boost-style hash_value via ADL."); + + typedef int NotHashable; + }; + + template + struct _HashImplementationSelector >::type > + : public __hash_base + { + size_t + operator() (TY const& elm) const noexcept + { + return hash_value(elm); + } + + }; + /** * Primary class template for std::hash. * We provide no default implementation, but a marker type @@ -62,16 +111,8 @@ namespace std { */ template struct hash - : public __hash_base - { - -/////// deliberately NOT defined to allow for SFINAE... -// -// static_assert (sizeof(TY) < 0, "std::hash is not specialized for this type"); -// size_t operator()(const _Tp&) const noexcept; - - typedef int NotHashable; - }; + : public _HashImplementationSelector + { }; } @@ -122,36 +163,12 @@ namespace std { #undef STD_HASH_IMPL } + + + + #include - - -namespace lib { -namespace meta { - - namespace { - struct NoUsableHashDefinition { size_t more_than_one[2]; }; - typedef size_t HasUsableHashDefinition; - - NoUsableHashDefinition hash_value(...); - - } - - template - class provides_BoostHashFunction - { - TY const& unusedDummy = *(TY*)nullptr; - - public: - enum{ value = (sizeof(HasUsableHashDefinition) == sizeof(hash_value(unusedDummy))) }; - }; -}} - -#include - - - -//#include #include #include #include @@ -218,7 +235,6 @@ main (int, char**) boost::hash boo_customHasher; std::hash boo2std_crossHar; - boost::hash std2boo_crossHar; cout << "raw hash(std) = " << std_stringHasher(p) <<"|"<< std_stringHasher(pp) << "\n (boost) = " << boo_stringHasher(p) <<"|"<< boo_stringHasher(pp) @@ -226,9 +242,14 @@ main (int, char**) << "\n custom hash (boost) " << boo_customHasher(v) <<"|"<< boo_customHasher(vv) << "\n has_boost_hash " << lib::meta::provides_BoostHashFunction::value << "\n has_boost_hash " << lib::meta::provides_BoostHashFunction::value -// << "\n use std from boost: " << std2boo_crossHar(s) <<"|"<< std2boo_crossHar(ss) -// << "\n use boost from std: " << boo2std_crossHar(v) <<"|"<< boo2std_crossHar(vv) + << "\n use boost from std: " << boo2std_crossHar(v) <<"|"<< boo2std_crossHar(vv) ; + +// Note: does not compile, +// since there is not automatic bridge from std to boost hash +// +// boost::hash()(s); + cout << "\n.gulp.\n"; return 0;