Использование boost :: tuple в tr1 :: hash - PullRequest
8 голосов
/ 18 ноября 2011

Я хочу определить std::tr1::hash<boost::tuple<A,B,C> >.Но я получаю ошибку, которая не появляется, когда я даю полную инстанцию.Вот код

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;
    }
};
}
}

Первый фрагмент выдает эту ошибку

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

, а второй компилируется просто отлично.Что не так с первым шаблоном?Я использую gcc 4.3.4.

Ответы [ 2 ]

8 голосов
/ 18 ноября 2011

Вам необходимо использовать ключевое слово .template:

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;
    }
};

Это необходимо, поскольку тип t зависит от трех параметров шаблона (и поэтому t зависит от типа), а get<0> - это название шаблона специализации.Из стандарта C ++ - §14.2/4:

Когда после имени появляется имя специализации шаблона члена.или -> в выражении postfix ... и выражение объекта выражения postfix зависит от типа ... имени шаблона элемента должно предшествовать ключевое слово template....

Это требование позволяет анализировать шаблоны до того, как станут известны их аргументы типа.

Например, рассмотрим:

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

БезПравило .template, это можно интерпретировать как две разные вещи:

//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)

Фактические правила позволяют однозначно анализировать f . set < 0 > ( 2 == 3 ) как последовательность операций сравнения.Они также означают, что t.get<0>() анализируется как t.get < 0 > ().expected primary-expression должен быть в пустом ().

6 голосов
/ 18 ноября 2011

У меня нет времени, чтобы проверить вещи, но я бы ожидал либо

std::get<0>(t)

, либо

boost::get<0>(t)

вместо t.get<0>()

Делайте квалификацию get (), даже если вы «используете» пространства имен, иначе ADL сильно повредит вам при смешивании библиотек, подобных этой.Смотри В чем подводные камни ADL?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...