如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?

Posted

技术标签:

【中文标题】如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?【英文标题】:How to use is_transparent feature on a string literal with unordered_map from std::string? 【发布时间】:2013-12-03 12:09:30 【问题描述】:

在 cppreference 上环顾四周,我发现 std::unordered_map gets efficient lookup 的功能来自“等效键”。

我认为这意味着等效键必须具有相同的哈希值。我如何才能为字符串文字提供与 std::hash<std::string> 相同的哈希值,而无需临时构造 std::string 从而使等效键的全部意义无效?

【问题讨论】:

乍一看,我发现有 2 个问题需要克服:1) 查找(以及其他 std::unordered_map 查找函数)都采用 Key const&,这将立即创建一个临时函数。 2) 字符串文字没有 std::hash 特化。我怀疑最好的答案是编写自己的容器,它类似于unordered_map,但允许按字符串文字进行搜索,并使用可以处理std::string(存储值)以及const char* 的自定义散列函数用于查找。 @DaveS 那么为什么 cppreference 说从 C++14 开始的 unordered_mapfind 有一个“等效键”的重载?我很困惑。我认为在open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3657.htm 上介绍is_transparent 的论文似乎没有为散列函数对象介绍它。另外,cppreference 谈到的Compare 是什么?我觉得我错过了一些重要的东西。我只是觉得很臭,即使在 C++14 中,我仍然需要为这些简单的问题编写自己的容器:( 是的,这个想法是您编写自己的哈希函数来涵盖所有等效类型。对于这个用例,无论如何我总是有一些“pair”。所以不要使用 std::hash,而是你自己的,这两种类型都有一个 op()。 @PlasmaHH 啊,我明白了。像这样:coliru.stacked-crooked.com/a/f80fefd2c6c51c2e。不幸的是,gcc 和 clang 似乎还不支持它:/ 我们确定std::hash 在 C++14 中获得了这种支持吗?您链接的论文仅显示在关联容器上,而不是无序容器上。尽管 cppreference 具有所有优点,但它还大量使用内部模板来减少重复。似乎mapunordered_map 都在使用相同的find 描述块,这解释了Compare::is_transparent 在描述中的使用。 【参考方案1】:

这是 cppreference 中的错误;对于无序的关联容器没有模板化查找。

比较,来自 n3690,

来自§23.5.4.1[unord.map.overview]

// lookup
iterator find(const key_type& k);
const_iterator find(const key_type& k) const;
size_type count(const key_type& k) const;

来自§23.4.4.1[map.overview]

// 23.4.4.5, map operations:
iterator find(const key_type& x);
const_iterator find(const key_type& x) const;
template <class K> iterator find(const K& x);
template <class K> const_iterator find(const K& x) const;
size_type count(const key_type& x) const;

【讨论】:

如果他们也添加无序关联容器就好了。它需要一个透明的KeyEqual 函数,还需要一个Hash,它支持Key 类型和模板化find 的输入。我认为指定后者会有点棘手。 @DaveS for unordered_set&lt; T, Hash, Equal &gt;, 如果Hash::is_transparent 添加unordered_set&lt; T, Hash, Equal &gt;::find&lt;K&gt;(const K&amp; x) 执行Hash(x) 然后Equal( y, x ) 其中y 是由Hash(x) 找到的元素?现在,x 必须是 Equal-able(通过转换或透明度),但是...【参考方案2】:

正如其他人所说,无序关联容器不支持is_transparent 模式。另一方面,Boost.MultiIndex 散列索引允许您想要的,如documentation 中所述,如果您可以选择用基于multi_index_container 的等效结构替换std::unordered_map

【讨论】:

【参考方案3】:

无序容器的异构查找已被 C++20 采用(p0919、p1690)。它已经在gcc 11.0 和clang 12.0 中可用。

【讨论】:

以上是关于如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用参数将 std::string 复制到 std::string?

带有自定义分配器的 std::string

真的没有来自 std::string_view 的 std::string 的显式构造函数吗?

std::string 是如何实现的?

基于文本的游戏 - std::string 来自新手的一些问题

发出带有 qt 信号的 std::string