2016-08-31 6 views
2

В следующем коде реализована хеш-функция для std::tuple, которая затем используется в другом сегменте моей кодовой базы в std::unordered_map от std::tuple.Проблема с недопустимым использованием неполного типа при использовании std :: tuple_element

// compute hash function recursively through each std::tuple element 
template<class Tuple, std::size_t N> 
struct tuple_hash_compute { 
    static std::size_t hash_compute(const Tuple& t) { 
     using type = typename std::tuple_element<N-1, decltype(t)>::type; // OFFENDING LINE 
     return tuple_hash_compute<Tuple, N-1>::hash_compute(t) 
      + std::hash<type>()(std::get<N-1>(t)); 
    } 
}; 
// base helper 
template<class Tuple> 
struct tuple_hash_compute<Tuple, 1> { 
    static std::size_t hash_compute(const Tuple& t) { 
     using type = typename std::tuple_element<0, decltype(t)>::type; // OFFENDING LINE 
     return 51U + std::hash<type>()(std::get<0>(t))*51U; 
    } 
}; 
// tuple_hash function object 
struct tuple_hash { 
    template<class... Args> 
    std::size_t operator()(const std::tuple<Args...>& t) const { 
     return tuple_hash_compute<decltype(t), sizeof...(Args)>::hash_compute(t); 
    } 
    // will use std::unordered_map of std::pair too, so overload reqd 
    template<class Ty1, class Ty2> 
    std::size_t operator()(const std::pair<Ty1, Ty2>& p) const { 
     return tuple_hash_compute<decltype(t), 2>::hash_compute(p); 
    } 
}; 

Тогда, только в качестве примера, я хотел бы использовать эту хэш-функцию-объект, как это так,

std::unordered_map<std::tuple<int,int,int>, std::size_t, tuple_hash> agg_map; 
agg_map.insert(std::make_pair(std::make_tuple(1,2,3), 0U)); 
agg_map.insert(std::make_pair(std::make_tuple(4,5,6), 1U)); 

Однако, в обоих GCC 6.1.0 и MSVC2015, получаю следующие ошибки (как то же самое для каждая линия обижая выше):

error: invalid use of incomplete type ' class std::tuple_element<2ul, const std::tuple<int,int,int>&> '

Я не совсем уверен, что вызывает эту ошибку (хотя это может быть связано с «абстракции» прохождения std::tuple V ia параметр шаблона Tuple) или как его можно решить, поэтому любая помощь будет оценена.

+0

Возможно, использовать 'Tuple' вместо' decltype (t) '? –

+0

@PiotrSkotnicki Боюсь, я уже пробовал это и получил ту же ошибку. – ArchbishopOfBanterbury

+1

http://coliru.stacked-crooked.com/a/655758eda525a016 –

ответ

3

Для параметра объявлены, как показано ниже:

const Tuple& t 

decltype(t) выходы:

const Tuple& 

Аналогично, для параметра объявлен как:

const std::pair<Ty1, Ty2>& t 

decltype(t) урожайности:

const std::pair<Ty1, Ty2>& 

В обоих случаях произведенный тип является ссылкой на тип, подобный кортежу. Однако std::tuple_element не специализирован для ссылок, а это означает, что компилятор возвращается к первичному, неопределенному шаблону класса:

template <size_t I, typename T> class tuple_element; 

То, что вы хотите, это в первом случае простой Tuple и std::pair<Ty1, Ty2> в последнем случае ,

+2

И если у вас есть случай, когда вам нужно использовать 'decltype', вы можете использовать' std :: decay_t '. – Oktalist