为什么std::set::extract不支持与std::set::find相同的异质查找功能
问题复现代码
#include <set> #include <string> #include <string_view> using namespace std::literals; int main() { auto coll = std::set<std::string, std::less<>>{"abc"s, "xyz"s}; coll.find("abc"sv); // 编译通过 coll.extract("abc"sv); // 编译报错 }
核心原因
这个差异本质是C++标准对std::set不同接口的设计差异导致的:
- 从C++14开始,只读类的查找接口(
find/count/contains/lower_bound等)就支持了异质查找特性:只要容器的比较器是透明的(比如示例中的std::less<>),就可以接受任意和Key类型可比较的参数,无需构造临时Key对象。 - 而
extract是C17才新增的接口,直到当前最新的C23标准,都没有为其添加异质查找的重载版本。标准中extract仅提供两个重载:- 接受迭代器参数的版本:
node_type extract(iterator pos) - 接受精确
Key类型常量引用的版本:node_type extract(const key_type& x)
- 接受迭代器参数的版本:
为什么标准不为extract增加异质重载?
主要有两方面的考量:
- 接口设计优先级问题:当初C++17引入
extract接口的核心目的是支持节点在容器之间的零拷贝转移,异质查找的支持不在当时的核心需求范围内,后续版本迭代中这个特性的优先级也一直低于其他特性,至今没有被纳入标准。 - 语义安全顾虑:
extract是会修改容器结构的可变操作,一旦调用成功就会把对应节点从容器中移除。如果支持异质参数,可能会出现用户传入的可比类型和Key语义匹配度不足的误调用情况,相比只读的find接口,这类误调用的后果要严重很多。
解决方案
如果想要用string_view这类异质参数提取节点,可以先通过异质find拿到迭代器,再将迭代器传入extract即可:
auto it = coll.find("abc"sv); if (it != coll.end()) { auto node = coll.extract(it); // 编译通过,无额外string构造开销 }
内容的提问来源于stack exchange,提问作者xmllmx
相关产品推荐
相关产品推荐

