2011-11-18 12 views
8

Quiero definir std::tr1::hash<boost::tuple<A,B,C> >. Pero aparece un error que no aparece cuando doy una instancia completa. Aquí está el códigoUso de boost :: tuple en tr1 :: hash

namespace std{ 

namespace tr1{ 
template<typename A, typename B, typename C> 
struct hash<boost::tuple<A,B,C> >{ 
    size_t operator()(const boost::tuple<A,B,C> &t) const{ 
     size_t seed = 0; 
     boost::hash_combine(seed, t.get<0>()); 
     boost::hash_combine(seed, t.get<1>()); 
     boost::hash_combine(seed, t.get<2>()); 
     return seed; 
    } 
}; 

template<> 
struct hash<boost::tuple<int,int,int> >{ 
    size_t operator()(const boost::tuple<int,int,int> &t) const{ 
     size_t seed = 0; 
     boost::hash_combine(seed, t.get<0>()); 
     boost::hash_combine(seed, t.get<1>()); 
     boost::hash_combine(seed, t.get<2>()); 
     return seed; 
    } 
}; 
} 
} 

La primera pieza da este error

unordered.hpp: In member function 'size_t std::tr1::hash<boost::tuples::tuple<A, B, C, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type> >::operator()(const boost::tuples::tuple<A, B, C, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>&) const': 
unordered.hpp:12: error: expected primary-expression before ')' token 
unordered.hpp:13: error: expected primary-expression before ')' token 
unordered.hpp:14: error: expected primary-expression before ')' token 

y el segundo recoge muy bien. ¿Qué pasa con la primera plantilla? Estoy usando gcc 4.3.4.

+0

¿No es 'std :: hash' una característica de C++ 11? En ese caso, puede usar 'std :: tuple' también. Creo que le falta una palabra clave 'typename'. – AJG85

+0

Creo que 'boost :: hash' ya está definido para' boost :: tuple's. Si está utilizando la biblioteca estándar, ¡use 'std :: tuple' también! –

+0

@ AJG85 Estoy usando gcc 4.3.4 donde 'hash' todavía está en' tr1' y 'tuple' está solo en boost. –

Respuesta

8

Es necesario utilizar el .template palabra clave:

template<typename A, typename B, typename C> 
struct hash<boost::tuple<A,B,C> >{ 
    size_t operator()(const boost::tuple<A,B,C> &t) const{ 
     size_t seed = 0; 
     boost::hash_combine(seed, t.template get<0>()); 
     boost::hash_combine(seed, t.template get<1>()); 
     boost::hash_combine(seed, t.template get<2>()); 
     return seed; 
    } 
}; 

Esto es necesario porque el tipo de t depende de tres parametros de plantilla (y por lo t es dependiente del tipo), y get<0> es el nombre de una especialización de plantilla. Desde el estándar C++: §14.2/4:

Cuando aparece el nombre de una plantilla de miembro especializada. o -> en una expresión de postfijo ... y la expresión de objeto de la expresión de postfijo depende del tipo ... el nombre de la plantilla de miembro debe ir precedido de la plantilla de palabra clave. ...

Este requisito existe para permitir que las plantillas se analicen antes de que se conozcan sus argumentos de tipo.

Por ejemplo, considere:

f . set <0> (2 == 3) 

Sin la regla .template, esto podría interpretarse como dos cosas diferentes:

//A call to an instantiation of a member function template 
//in this case equivalent to f.template set<0>(false) 
f.set<0>(2 == 3) 
//A series of comparison operations, in this case equivalent to 
//f.set < 0 
f.set <0> (2 == 3) 

Las normas actuales permiten f . set <0> (2 == 3) a ser analizado de forma inequívoca como una serie de comparación operaciones. También significan que t.get<0>() se analiza como t.get <0>(). El expected primary-expression está destinado a estar en el () vacío.

6

no tengo tiempo para comprobar las cosas, pero yo esperaría que sea

std::get<0>(t) 

o

boost::get<0>(t) 

en lugar de t.get<0>()

Hazcalificar get() incluso si está 'usando' espacios de nombres, o ADL le hará mucho daño al mezclar bibliotecas como esta . Ve What are the pitfalls of ADL?

+0

De hecho, usando' boost :: get' funcionó. ¿Por qué? –

+0

Consulte http://stackoverflow.com/questions/2958648/what-are-the-pitfalls-of-adl y menor quizás las diferencias de interfaz entre std :: tuple y boost :: tuple. Sé que hay diferencias para std :: basic_regex <> también – sehe

Cuestiones relacionadas