为什么没有透明的C++ std::map::at?

Why no transparent C++1x std::map::at?

提问人:bobah 提问时间:11/23/2016 最后编辑:Communitybobah 更新时间:2/4/2023 访问量:638

问:

中缺少透明()有原因吗?template <class K> at(K&& key);std::map

C++ 11 C +14 语言律师

评论

1赞 Slava 11/23/2016
它也没有透明operator[]
0赞 StoryTeller - Unslander Monica 11/23/2016
@Slava,但它确实有一个透明的.find
1赞 SergeyA 11/23/2016
我不想要它。键是一种特定类型,我不想要一个模板化的函数,它会接受任何东西,只是在我输入错误参数时给我几张错误。
0赞 SergeyA 11/23/2016
@StoryTeller,这是非常不同的。 应该是透明的,仅仅是因为表示为显式循环的相同发现将是透明的。find
3赞 StoryTeller - Unslander Monica 11/23/2016
@SergeyA 在 c++14 之前,它预计不会是透明的。对于这两个操作,我们隐式转换为。这是一个有效的问题和对比。Key

答:

11赞 Leon 11/23/2016 #1

我的猜测是,这一定是 .提供 的透明版本对查询键类型施加了额外的要求 - 如果查询键不在映射中,则必须插入它(使用默认构造值),这意味着必须可从查询键类型构造。std::map::at()std::map::operator[]()std::map::operator[]()std::map::key_typeKstd::map::key_type

评论

6赞 Leon 11/23/2016
@SergeyA 这两种类型不需要可转换 - 它们只需要通过透明的比较器进行比较。
5赞 SergeyA 11/23/2016
这确实是正确的!我会把我的评论留在那里供未来的读者使用,但它在逻辑上被撤回了。
3赞 T.C. 11/24/2016
此外,与同类情况不同,不要求异构密钥与映射中的最多一个密钥等效。如果多个键是匹配的,则返回什么?
1赞 krzaq 11/24/2016
@T.C.同样的论点也可以提出,但有一个透明的.findfind
4赞 T.C. 11/24/2016
@krzaq,除了这也是多地图的既定操作。find
3赞 Emile Cormier 2/3/2023 #2

P2363 建议为 、 、 、 和 (后者用于无序映射)添加异构密钥重载。它错过了包含在 C++23 中,并且在 C++26 中被标记为待处理attry_emplaceinsert_or_assignoperator[]insertbucket

可以在 Github 上找到对 P2363 进行的评论摘要。对不起,我不知道如何找到原始评论;它甚至可能不公开。

在该评论摘要中,有以下评论:

目前,对于异构查找,唯一键关联容器不要求最多有一个匹配项......

我认为这篇论文应该讨论在这种情况下会发生什么,特别是对于insert_or_assign、运算符[]和在(以及try_emplace失败时会返回什么)

我相信该注释回答了为什么没有为 C++14 或 C++17 提供异质重载。at()


我的结论(与T.C.在另一个答案中的评论不谋而合):

std::map 的异构查找目前不要求最多有一个匹配项。对于该函数,此类查找必须:at()

  • 被限制为 0..1 个匹配项,或者,
  • 访问满足键等效性条件的第一个元素(如果未找到,则抛出)。

对于行为应该是什么可能没有达成共识,这可能就是为什么在 C++14 和 C++17 中引入异构键的提案中被排除在外的原因。或者,也许他们认为这在语义上只对访问一个没有歧义的独特元素有意义(这就是多地图中没有的原因)。at()atat

请注意,在编译时无法检查异构密钥是否最多匹配一个元素。


作为参考,这是为 C++14 引入异构键的提案:N3657 向关联容器添加异构比较查找。其中没有提到。at()

这是在 C++20 中引入无序容器异构查找的提案:P0919 无序容器的异构查找

这是引入异构密钥进行擦除的提案:P2077 关联容器的异构擦除重载,标记为已批准用于 C++23。