unsuccessful attempt to bridge between std::hash and boost::hash_value (Ticket #722)

This commit is contained in:
Fischlurch 2014-04-03 22:43:35 +02:00
parent 7be1b7d35d
commit 44970ed96e
3 changed files with 139 additions and 0 deletions

View file

@ -55,6 +55,7 @@
#define LIB_HASH_INDEXED_H
#include "lib/hash-value.h"
#include "lib/hash-standard.hpp"
extern "C" {
#include "lib/luid.h"
@ -208,4 +209,24 @@ namespace lib {
} // namespace lib
/////////////////////////////////////////////////////////////////////////TICKET #722 : should provide a generic bridge to use hash_value
// The following doesn't work as expected, probably because of sub type relationship not being detected when picking a template specialisation
// see also hash-standard.hpp
//namespace std {
//
// template<typename BA, typename IMP>
// struct hash<lib::HashIndexed<BA,IMP> >
// {
// size_t
// operator() (lib::HashIndexed<BA,IMP> const& val) const noexcept
// {
// return hash_value(val);
// }
// };
//
//}
#endif

104
src/lib/hash-standard.hpp Normal file
View file

@ -0,0 +1,104 @@
/*
HASH-STANDARD.hpp - allow use both of std and boost hasher implementations
Copyright (C) Lumiera.org
2014, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file hash-standard.hpp
** Helper to use a single extension point for specialised hash functions.
** With the switch to C++11, there are now two competing quasi standard frameworks
** for defining individual hasher functions: the \c std::hash functor and \c <boost/functional/hash.hpp>.
** The standard library hasher is used by the (new) STL hashtables and requires an explicit
** specialisation of \c std::hash<TYPE>, while the boost hash automatically picks up an
** free function `hash_value(MyType const&)`. Additionally, Boost ships with a large collection
** of predefined hash functions for various combinations of standard containers and custom types.
** To add to this venerable mess, the standard hash defines a default specialisation which
** triggers a static assertion and halts compilation, in case no custom specialisation
** can be found.
**
** In the Lumiera code base, the habit is to define a free function \c hash_value alongside with
** custom data types. This helper uses metaprogramming to generate a bridge from the standard hasher
** to use this boost-style custom hash function if applicable.
**
** @todo 4/2014 doesn't work as expected. My suspicion is that in the actual use case (PlacementIndex),
** the type providing the hasher is mixed in through inheritance, and the template specialisation
** for this base type is not considered on lookup. ///////TICKET #722
**
** @see HashIndexed
** @see LUID
**
*/
#ifndef LIB_HASH_STANDARD_H
#define LIB_HASH_STANDARD_H
#include "lib/hash-value.h"
#include "lib/meta/util.hpp"
#include <boost/utility/enable_if.hpp>
//#include <boost/functional/hash.hpp>
#include <functional>
namespace lib {
namespace meta {
template <typename T>
struct has_boost_hash_subst { typedef void* Type; };
template<typename TY>
struct provides_BoostHasher
{
template<class X>
static Yes_t check(typename has_boost_hash_subst<decltype(hash_value(X()))>::Type);
template<class>
static No_t check(...);
enum{ value = (sizeof(Yes_t)==sizeof(check<TY>(nullptr))) };
};
}}
namespace std {
/////////////////////////////////////////////////////////////////////////TICKET #722 : attempt to provide a generic bridge to use hash_value
//
// this was my first attempt 4/2014, but doesn't work, probably because of the actual ID being inherited
// see also the attempt at the bottom of hash-indexed.hpp
template<typename TY>
struct hash< boost::enable_if<lib::meta::provides_BoostHasher<TY>,
TY > >
{
size_t
operator() (TY const& val) const noexcept
{
return hash_value(val);
}
};
}
#endif

View file

@ -117,6 +117,20 @@
#include <boost/scoped_ptr.hpp>
#include <vector>
namespace std {
/////////////////////////////////////////////////////////////////////////TICKET #722 : should provide a generic bridge to use hash_value
template<>
struct hash<proc::mobject::PlacementMO::ID>
{
size_t
operator() (proc::mobject::PlacementMO::ID const& val) const noexcept
{
return hash_value(val);
}
};
}
namespace proc {
namespace mobject {