【问题标题】:Issue with invalid use of incomplete type when using std::tuple_element使用 std::tuple_element 时无效使用不完整类型的问题
【发布时间】:2016-08-31 17:26:52
【问题描述】:

以下代码实现了 std::tuple 的哈希函数,然后在 std::unordered_mapstd::tuples 的 std::unordered_map 中用于我的代码库的不同段。

// 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.0MSVC2015 中,我都收到以下错误(以上每个违规行都相同):

错误:不完整类型'class std::tuple_element&lt;2ul, const std::tuple&lt;int,int,int&gt;&amp;&gt;'的使用无效

我不完全确定是什么导致了这个错误(尽管它可能是由于通过模板参数std::tuple 传递std::tuple 的“抽象”)或如何解决它,因此感谢您的帮助。

【问题讨论】:

  • 也许使用Tuple 而不是decltype(t)
  • @PiotrSkotnicki 恐怕我已经尝试过了并且收到了同样的错误。
  • @PiotrSkotnicki 嗯,有趣,好的,我现在可以在GCC 中使用它(也许我以某种方式错过了相关的#include)但它仍然不喜欢MSVC2015 - 我在这种情况下得到use of undefined type std::tuple_element&lt;2, Tuple&gt; 作为错误。
  • @PiotrSkotnicki 啊,没关系,我没有意识到你也替换了那行 - 它现在在 GCC 和 MSVC 中都可以使用,谢谢 :) 把它写成答案,我会接受它(一旦我吃完饭回来),虽然我很好奇为什么这种改变会起作用。

标签: c++ c++14 stdtuple stdhash


【解决方案1】:

对于声明如下的参数:

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&lt;Ty1, Ty2&gt;

【讨论】:

  • 如果你有需要使用decltype的情况,你可以使用std::decay_t&lt;decltype(t)&gt;
【解决方案2】:

如果您对可能是也可能不是引用的类型 Tuple 有此问题,您可以像这样使用 std::remove_reference

typename std::tuple_element<num, typename std::remove_reference<Tuple>::type>::type

或者,对于 C++17,

std::tuple_element_t<num, std::remove_reference_t<Tuple>>

PS:我认为它不适用于 std::reference_wrapper...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 2010-10-13
    • 2017-10-24
    • 2013-05-19
    • 2016-04-06
    • 2017-07-28
    相关资源
    最近更新 更多