无法创建元组的 unordered_map<int, int, int>

Posted

技术标签:

【中文标题】无法创建元组的 unordered_map<int, int, int>【英文标题】:Cannot create unordered_map of tuple<int, int, int> 【发布时间】:2012-04-19 23:47:12 【问题描述】:

我正在使用std::unordered_map&lt;std::tuple&lt;int, int, int&gt;, float&gt;。但是,VS2010 不会编译实例化。我明确提供了hash 特化和operator== 重载。错误信息指的是

std::unordered_map<NodeType, float> g_score;

这是错误的全文:

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple(127): error C2440: 'initializing' : cannot convert from 'const NodeType' to 'int'
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\xxtuple0(9) : see reference to function template instantiation 'std::tr1::_Cons_node<_Car,_Cdr>::_Cons_node<_Ty,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&>(_Farg0 &&,_Farg1,_Farg2,_Farg3,_Farg4,_Farg5,_Farg6,_Farg7,_Farg8,_Farg9)' being compiled
1>          with
1>          [
1>              _Car=int,
1>              _Cdr=std::tr1::_Cons_node<int,std::tr1::_Cons_node<int,std::tr1::_Tuple_type<std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>::_Type>>,
1>              _Ty=NodeType,
1>              _Farg0=NodeType,
1>              _Farg1=std::tr1::_Nil &,
1>              _Farg2=std::tr1::_Nil &,
1>              _Farg3=std::tr1::_Nil &,
1>              _Farg4=std::tr1::_Nil &,
1>              _Farg5=std::tr1::_Nil &,
1>              _Farg6=std::tr1::_Nil &,
1>              _Farg7=std::tr1::_Nil &,
1>              _Farg8=std::tr1::_Nil &,
1>              _Farg9=std::tr1::_Nil &
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(145) : see reference to function template instantiation 'std::tr1::tuple<_Arg0,_Arg1,_Arg2>::tuple<const std::tr1::tuple<_Arg0,_Arg1,_Arg2>>(_Farg0 &&)' being compiled
1>          with
1>          [
1>              _Arg0=int,
1>              _Arg1=int,
1>              _Arg2=int,
1>              _Farg0=const std::tr1::tuple<int,int,int>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(142) : while compiling class template member function 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base(const std::tr1::tuple<_Arg0,_Arg1,_Arg2> &&,float &&)'
1>          with
1>          [
1>              _Ty1=const NodeType,
1>              _Ty2=float,
1>              _Arg0=int,
1>              _Arg1=int,
1>              _Arg2=int
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(174) : see reference to class template instantiation 'std::_Pair_base<_Ty1,_Ty2>' being compiled
1>          with
1>          [
1>              _Ty1=const NodeType,
1>              _Ty2=float
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\unordered_map(279) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
1>          with
1>          [
1>              _Ty1=const NodeType,
1>              _Ty2=float
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\unordered_map(275) : while compiling class template member function 'float &std::tr1::unordered_map<_Kty,_Ty>::operator [](const std::tr1::tuple<_Arg0,_Arg1,_Arg2> &)'
1>          with
1>          [
1>              _Kty=NodeType,
1>              _Ty=float,
1>              _Arg0=int,
1>              _Arg1=int,
1>              _Arg2=int
1>          ]
1>          c:\repo\render\render\sim\simcontext.cpp(155) : see reference to class template instantiation 'std::tr1::unordered_map<_Kty,_Ty>' being compiled
1>          with
1>          [
1>              _Kty=NodeType,
1>              _Ty=float
1>          ]
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple(127): error C2439: 'std::tr1::_Cons_node<_Car,_Cdr>::_Value' : member could not be initialized
1>          with
1>          [
1>              _Car=int,
1>              _Cdr=std::tr1::_Cons_node<int,std::tr1::_Cons_node<int,std::tr1::_Tuple_type<std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>::_Type>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple(170) : see declaration of 'std::tr1::_Cons_node<_Car,_Cdr>::_Value'
1>          with
1>          [
1>              _Car=int,
1>              _Cdr=std::tr1::_Cons_node<int,std::tr1::_Cons_node<int,std::tr1::_Tuple_type<std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>::_Type>>
1>          ]

不确定从哪里继续,因为我以前从未见过此错误。有什么建议吗?

编辑:有趣的是,在此之前的 unordered_set&lt;NodeType&gt; 可以干净地编译。

试试这个SSCCE:

#include <deque>
#include <tuple>
#include <unordered_map>
#include <unordered_set>

void GetPath() 
    typedef std::tuple<int, int, int> NodeType;
    struct node_hasher : public std::unary_function<const NodeType&, std::size_t> 
        std::size_t operator()(const NodeType& node) const 
            return std::hash<int>()(std::get<0>(node) + std::get<0>(node) + std::get<0>(node) + std::get<1>(node) + std::get<1>(node) + std::get<2>(node));
        
    ;
    std::unordered_set<NodeType, node_hasher> closed_set;
    std::unordered_map<NodeType, float, node_hasher> g_score;
    std::unordered_map<NodeType, float, node_hasher> f_score;
    std::unordered_map<NodeType, NodeType, node_hasher> came_from;
    auto node_comparator = [&](NodeType lhs, NodeType rhs) 
        return f_score[lhs] < f_score[rhs];
    ;


int main() 

在空项目中编译失败并出现同样的错误。如果您取消注释 node_comparator lambda,它就可以正常工作。难怪我遇到了麻烦——这是另一个 VS 错误。

【问题讨论】:

std::unordered_map&lt;std::tuple&lt;int, int, int&gt;&gt; 我认为你在这里遗漏了一些东西。 您正在为 std::hash&lt;&gt; 专门用于位于命名空间 std 中的类型? @ildjarn:我希望对它进行哈希处理,但它没有自己的哈希专业化。你说我还能做什么? 您应该编写自己的哈希函子并将其传递给std::unordered_map&lt;&gt;(注意第3个和第4个模板参数);你现在尝试做的事情是非法的。 然后发布SSCCE。你比这更清楚。 【参考方案1】:

这是 Visual C++ 2010 标准库中的一个错误。请参阅以下有关 Microsoft Connect 的报告:

C++ map&lt;tuple&lt;...&gt;, V&gt; compilation problems

已针对 Visual Studio 11 修复了该错误。您的示例使用 Visual Studio 11 Beta 编译时没有错误。

【讨论】:

【参考方案2】:

提示...将散列和相等实现为 lambda,然后使用这些 lambda 的类型作为模板参数:

auto h = [](const TKey& x)  ... ;
auto eq = [](const TKey& x, const TKey& y)  ... ;

std::unordered_map<TKey, TValue, decltype(h), decltype(eq)> m;

【讨论】:

+1:不像我,听起来你正在测试你的建议。 :-)【参考方案3】:

尝试将NodeTypenode_hasher 移动到命名空间范围。在 C++03 中,局部类型不能用作模板参数。也许 VS2010 还没有实现那个改变。我只是猜测。我没有 VS2010,因此没有用你的 SSCCE 尝试过这个实验。

【讨论】:

FWIW 编译:int main() struct foo; std::vector&lt;foo&gt; v; v.push_back(foo()); 。是否只是疏忽了 hash 没有为对和元组定义? Visual C++ 2010 支持将本地类型用于模板参数(如果不支持,则 lambda 表达式在 STL 算法中无法很好地工作)。此功能可能存在错误,但我不记得遇到过任何错误。 @GManNickG:监督是一个公平的声明。虽然超时可能更准确。在看不到标准的 2009 年过去之后,委员会的气氛非常类似于急需发布的软件项目。委员会不愿意引入新功能,除非可以证明不包括所述新功能将是灾难性的。在那个时间范围内,通过提案所需的工作量非常大。所以提议者将只处理他最优先的问题。 @JamesMcNellis:我很好奇是否有人真的在 DeadMG 的代码上进行过实验,结果如何。也许有一个 lambda/local-type/template-instantiation 错误。 或许不是。这只是一种预感。 @HowardHinnant:这么想,有道理。

以上是关于无法创建元组的 unordered_map<int, int, int>的主要内容,如果未能解决你的问题,请参考以下文章

Python的列表和元组的区别

tuple 元组

如何在 std::tuple 中合并 std::unordered_map?

如何从具有子元组的元组创建列表?

Python中的元组(Tuple)

Python-元组学习笔记(完)