c++ - ¿Cómo extender std:: tr1:: hash para tipos personalizados?
(4)
¿Cómo permito que la implementación de STL recoja mis tipos personalizados? En MSVC, hay una clase std::tr1::hash
, que puedo especializar parcialmente usando
namespace std
{
namespace tr1
{
template <>
struct hash<MyType>
{ ... };
}
}
¿Pero es esta la forma recomendada? Además, ¿esto funciona también con la implementación de GCC? Para boost::hash
, es suficiente para proporcionar una función gratuita size_t hash_value (const MyType&)
, ¿hay algo similar para la implementación de TR1?
Como no está agregando al std
nombres de la biblioteca estándar, sino que solo proporciona las especializaciones, entonces está perfectamente bien.
Si desea proporcionar un enfoque de hashing más genérico (por ejemplo, hash para las tuplas en general), eche un vistazo a Boost Fusion. Aquí hay un ejemplo simple , que funcionará para la mayoría de los casos (probablemente con la excepción de tupla de tuplas)
El siguiente fragmento de código muestra cómo especializar std::tr1::unordered_map
para mapear boost::const_string<char>
to void*
análoga a la forma en que se hash std::string
.
#include <boost/const_string/const_string.hpp>
typedef class boost::const_string<char> csc;
namespace std
{
namespace tr1
{
template <>
struct hash<csc> {
public:
size_t operator()(const csc & x) const {
return std::_Hash_impl::hash(x.data(), x.size());
}
};
}
}
typedef std::tr1::unordered_map<csc, void*> Map;
typedef Map::value_type Dual; ///< Element Type.
Estaba tratando de averiguar la sintaxis exacta para hacer esto con los contenedores asociativos desordenados (también utilizando GCC, como lo pedía el OP) y golpeé esta pregunta.
Desafortunadamente, no se redujo al nivel de detalle que quería. Mirando a través de los encabezados de gcc cómo implementaron las funciones hash estándar, funcionó. En vista de la escasez de ejemplos (al menos al momento de escribir) en la web, pensé que este sería un lugar tan bueno como cualquiera para publicar mi propio ejemplo (que puedo confirmar que funciona con GCC):
namespace std { namespace tr1
{
template <>
struct hash<MyType> : public unary_function<MyType, size_t>
{
size_t operator()(const MyType& v) const
{
return /* my hash algorithm */;
}
};
}}
(note que hay dos espacios de nombres aquí, esa es mi convención para contraer espacios de nombres anidados)
Sí, esto también funcionará para GCC. Lo estoy usando en un proyecto más grande y funciona sin problemas. También puede proporcionar su propia clase de hash personalizada para los contenedores TR1, pero se especifica que std :: tr1 :: hash <> es la clase de hashing predeterminada. La especialización para tipos personalizados parece ser la forma natural de extender la funcionalidad de hash estándar.