C++17 中 std::unordered_map 的推导指南

Posted

技术标签:

【中文标题】C++17 中 std::unordered_map 的推导指南【英文标题】:Deduction guides for std::unordered_map in C++17 【发布时间】:2017-09-16 08:48:12 【问题描述】:

我已经阅读了关于使用 cppreference 的 C++17 中 std::unordered_map 的推导指南。

然后尝试运行以下示例,该示例是从 cppreference 复制的。

#include <unordered_map>
int main() 
// std::unordered_map m1 = "foo", 1, "bar", 2; // Error: braced-init-list has no type
                                                     // cannot deduce pair<const Key, T> from
                                                     // "foo", 1 or "bar", 2
   std::unordered_map m1 = std::initializer_list<
                        std::pair<char const* const, int>>("foo", 2, "bar", 3); // guide #2
   std::unordered_map m2(m1.begin(), m1.end()); // guide #1

但是,编译器给出了错误。

main.cpp: In function 'int main()':
main.cpp:7:84: error: class template argument deduction failed:
                         std::pair<char const* const, int>>("foo", 2, "bar", 3); // guide #2
                                                                                    ^
main.cpp:7:84: error: no matching function for call to 'unordered_map(std::initializer_list<std::pair<const char* const, int> >)'
In file included from /usr/local/include/c++/7.2.0/unordered_map:48:0,
                 from main.cpp:1:
/usr/local/include/c++/7.2.0/bits/unordered_map.h:101:11: note: candidate: template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_map(std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>)-> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>
     class unordered_map
           ^~~~~~~~~~~~~

为什么编译器会报错?

【问题讨论】:

永远不要在地图中使用 char* 作为键。 @manni66: ...除非你真的知道你在做什么。 libstdc++ 尚未为其无序关联容器实现推导指南。 (而这些容器恰好是以阻止隐式指南工作的方式实现的。) @manni66 演绎指南可以轻松将字符指针更改为std::string... 【参考方案1】:

编辑:在与 GCC C++ 库 (libstdc++) 的开发人员讨论该问题后,我正在更新此答案。编辑后的答案更详细、更合理、更有方向。

从技术上讲,这是 GCC 中的编译器错误,而 clang 坚持标准。您的代码中的第一个指南适用于 clang-6 -stdlib=libc++。

std::unordered_map m1 = std::initializer_list<
                        std::pair<char const* const, int>>("foo", 2, "bar", 3); // guide #2

也是这样

std::unordered_map m2
std::pair<char const* const, int>"foo", 2, "bar", 3; // guide #2

但 GCC 偏离标准,允许:

std::unordered_map m2std::pair"foo", 2, "bar", 3;

实际上是一样的

// not const char*const, but rather const char*
std::unordered_map m2std::pair<const char*, int>"foo", 2, "bar", 3;

这不符合标准,因为该对的关键部分应该是 const。这实际上比标准要好,因为这种偏差使得推导模板参数成为可能。这与标准指南相反,如果不显式编写它们,就无法推断出std::unordered_map 模板参数,这是非常没用的。

图书馆工作组 (LWG) 页面 Issue 3025: Map-like container deduction guides should use pair<Key, T>, not pair<const Key, T> 提到了此问题。 GCC 只是决定使用不符合标准的扣除指南,这使该功能变得有用,而不是坚持使用符合标准的有用指南。

这个问题很可能很快就会有正式的 DR,使 GCC 的实现符合修订后的标准。

注意:您可以阅读GCC bug report 中有关此问题的详细信息,了解更多详细信息。

附:我希望您知道自己在做什么,制作const char* 类型的密钥。

【讨论】:

以上是关于C++17 中 std::unordered_map 的推导指南的主要内容,如果未能解决你的问题,请参考以下文章

在 Qt Android 中使用 C++17

C++17 中函数指针的求值顺序

Visual Studio 中基于 For 循环的 C++17 广义范围

C++17 中 std::unordered_map 的推导指南

c++17 聚合初始化

为啥 C++17 中的全局内联变量和静态内联成员需要守卫?