2011-11-06 4 views
22

I just me encontré un poco sorprendido al no poder utilizar simplemente un¿No hay especializaciones de std :: hash para contenedores estándar?

std::unordered_set<std::array<int, 16> > test; 

porque no parece ser una especialización std::hash para std::array s. ¿Porqué es eso? ¿O simplemente no lo encontré? Si no hay ninguno, ¿se puede simplificar el siguiente intento de implementación?

namespace std 
{ 
    template<typename T, size_t N> 
    struct hash<array<T, N> > 
    { 
     typedef array<T, N> argument_type; 
     typedef size_t result_type; 

     result_type operator()(const argument_type& a) const 
     { 
      hash<T> hasher; 
      result_type h = 0; 
      for (result_type i = 0; i < N; ++i) 
      { 
       h = h * 31 + hasher(a[i]); 
      } 
      return h; 
     } 
    }; 
} 

Realmente siento que esto debería de alguna manera ser parte de la biblioteca estándar.

+3

Realmente no hay uno, solo 'std :: string' y amigos tienen ese privilegio. ¿Sería realmente impopular si dijera que el esfuerzo de C++ por arrastrarse hacia el estado actual del arte en términos de estructuras de datos estándar todavía no ha hecho todo el trabajo? En realidad, no hay ninguna especialización '' hash' requerida para las plantillas (y que a su vez requeriría que sus argumentos de plantilla sean aptos para ser procesados). Las únicas especializaciones requeridas son para tipo incorporado y cuatro clases de cuerdas de hormigón. Entonces sospecho que una línea fue dibujada allí. –

+0

@Steve: ¿Cuáles 4 clases de cuerdas concretas? – fredoverflow

+2

'cadena',' u16string', 'u32string',' wstring' (21.6 en C++ 11). Yo diría que 'pair' y' tuple' deberían ser los siguientes objetivos de mayor prioridad, seguidos de los contenedores estándar, seguidos por un hash predeterminado para cualquier tipo agregado compuesto por miembros hashable. –

Respuesta

11

No estoy seguro de por qué la biblioteca estándar no ha incluido esto, pero Boost tiene hashing para todo tipo de cosas compuestas de tipos hashable. La función clave para esto es hash_combine, que puede copiar desde boost/functional/hash/hash.hpp.

Utilizando hash_combine, Boost obtiene range_hash (solo combina los valores hash de cada elemento de un rango), así como también hashers pares y tuplas. El range_hash a su vez se puede utilizar para hash cualquier contenedor iterable.

+8

Sí, 'range_hash' suena como debería estar en el estándar. – fredoverflow

11

No es una respuesta, pero sí algo de información útil. El proyecto de febrero del estándar C++ 11 especifica que std::hash está especializada para estos tipos:

  • error_code § 19.5.5
  • bitset<N> § 20.5.3
  • unique_ptr<T, D> § 20.7.2.36
  • shared_ptr<T, D> § 20.7.2.36
  • type_index § 20.13.4
  • string § 21.6
  • u16string § 21.6
  • u32string § 21.6
  • wstring § 21.6
  • vector<bool, Allocator> § 23.3.8
  • thread::id § 30.3.1.1

Y todos estos tipos: § 08/20/12

template <> struct hash<bool>; 
template <> struct hash<char>; 
template <> struct hash<signed char>; 
template <> struct hash<unsigned char>; 
template <> struct hash<char16_t>; 
template <> struct hash<char32_t>; 
template <> struct hash<wchar_t>; 
template <> struct hash<short>; 
template <> struct hash<unsigned short>; 
template <> struct hash<int>; 
template <> struct hash<unsigned int>; 
template <> struct hash<long>; 
template <> struct hash<long long>; 
template <> struct hash<unsigned long>; 
template <> struct hash<unsigned long long>; 
template <> struct hash<float>; 
template <> struct hash<double>; 
template <> struct hash<long double>; 
template<class T> struct hash<T*>; 
Cuestiones relacionadas