I want to define std::tr1::hash<boost::tuple<A,B,C> >
. But I get an error that doesn't appear when I give a complete instantation. Here's the code
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;
}
};
}
}
The first piece gives this 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
and the second compiles just fine. What's wrong with the first template? I'm using gcc 4.3.4.
You need to use the .template
keyword:
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;
}
};
This is required because type of t
depends on three template paramaters (and so t
is type-dependent), and get<0>
is the name of a template specialization. From the C++ standard -- §14.2/4
:
When the name of a member template specialization appears after . or -> in a postfix-expression ... and the object expression of the postfix-expression is type-dependent ... the member template name must be prefixed by the keyword template. ...
This requirement exists to allow templates to be parsed before their type arguments are known.
For example, consider:
f . set < 0 > ( 2 == 3 )
Without the .template
rule, this could interpreted as two different things:
//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)
The actual rules allow f . set < 0 > ( 2 == 3 )
to be unambiguously parsed as a series of comparison operations. They also mean that t.get<0>()
is parsed as t.get < 0 > ()
. The expected primary-expression
is meant to be in the empty ()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With