2012-01-01 7 views
10

que estoy tratando de hacer lo siguiente:Cómo hacer unordered_map impulso para soportar el peso mosca <string>

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> > map; 

     boost::flyweight<std::string> foo(name); 
     map[foo] = foo; 

Pero el compilador se queja: "C2665 de error: 'boost :: hash_value': ninguno de los 17 sobrecargas podía convierta todos los tipos de argumentos ".

Pero he definido la siguiente función:

std::size_t hash_value(const boost::flyweight<std::string> & b) 
{ 
    boost::hash<std::string> hasher; 
    const std::string & str = b.get(); 
    return hasher(str); 
} 
bool operator==(const boost::flyweight<std::string>& f, const boost::flyweight<std::string> & second) 
{ 
    return f.get() == second.get(); 
} 

Pero Indiferente compilar.

¿Qué debo hacer para aumentar boost unordered_map para admitir flyweight?

[EDIT] lo tengo para trabajar con el siguiente código:

struct flyweight_hash 
    { 
     std::size_t operator()(const boost::flyweight<std::string> &elm) const 
     { 
      boost::hash<std::string> hasher; 
      const std::string & str = elm.get(); 
      return hasher(str); 
     } 
    }; 

y se lo pasó como un parámetro de plantilla para la construcción del mapa:

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> , flyweight_hash > map; 

En este caso yo No entiendo cómo sobrecargar hash_value no funcionó.

Respuesta

7

boost::hash llama a hash_value a través de búsqueda dependiente de argumento (ADL). Está intentando definir una función hash_value para una clase en el espacio de nombres boost. Por lo tanto, su función hash_value debería ir a este espacio de nombres para que ADL funcione. Desafortunadamente, agregar funciones a un espacio de nombres extranjero es bastante malo y debe evitarse. Su solución de usar un hasher personalizado parece estar bien.

Un poco de código de ejemplo para ilustrar:

namespace boost { 
    // somewhere in boost 
    template<typename T> 
    std::size_t hash(const T& t) { 
    // call using ADL 
    // e.g. if called with object of class type foo::bar this will 
    // pick up foo::hash_value despite the lack of namespace 
    // qualification 
    return hash_value(t); 
    } 
} 

// your hash_value (presumably in the global namespace) 
// not picked up by above call 
std::size_t hash_value(boost::flyweight<T>...); 

namespace boost { 
    // this would be picked up but is slightly evil 
    std::size_t hash_value(boost::flyweight<T>...); 
} 
+0

Solo es malo porque 'hasher predeterminado de' boost :: unordered_map' no parece desencadenar ADL by 'using boost :: hash_value; return hash_value (clave); '. Sin embargo, no puedo verificar eso en este momento. – Xeo

+0

@Xeo El hasher predeterminado debe ser 'boost :: hash' y no debe ser específico de' unordered_map'. Al menos el doctor lo dice. – pmr

+0

Claro, pero eso no cambia que las llamadas habilitadas para ADL no parezcan ser utilizadas. – Xeo

5

es una lástima para discutir algo que ya ha sido desmenuzada. Flyweight mantiene una sola instancia de objetos iguales, por lo que es más eficiente copiar la dirección de esta instancia en lugar de su contenido. Hago la siguiente (en std, no en boost, como estoy usando C++ 11, así que estoy extendiendo std::hash, no boost::hash):

namespace std 
{ 
    template <typename T> 
    struct hash<boost::flyweight<T, boost::flyweights::no_tracking>> 
    { 
    using value_type = boost::flyweight<T, boost::flyweights::no_tracking>; 
    size_t operator()(const value_type& ss) const 
    { 
     hash<const void*> hasher; 
     return hasher(&ss.get()); 
    } 
    }; 
} 

Se me ha confirmado que se trabaja en el diseño, no por accidente: http://lists.boost.org/boost-users/2013/03/78007.php

Cuestiones relacionadas