为何std::unordered_set的erase方法无法使用透明查找参数(如字符串字面量),而find方法可以正常编译?
为何std::unordered_set的erase方法无法使用透明查找参数(如字符串字面量),而find方法可以正常编译?
这个问题其实是C++标准版本对容器方法的支持时间差导致的,我来给你拆解得明明白白:
1. 核心差异:两个方法的异构重载支持时期不同
你遇到的编译失败本质是标准的历史问题:
find的异构查找:也就是直接传非容器key_type的参数(比如你的字符串字面量"42"),在C++14就已经被加入标准了。只要你给unordered_set配置了透明哈希函数(带is_transparent标记)和透明比较器(比如你用的std::equal_to<>),编译器就能匹配到对应的模板重载,所以uset.find("42")能正常编译。erase(K&& x)的异构重载:这个能直接传非key_type参数的erase版本,是直到C++20才被加入标准的!在C++20之前,unordered_set::erase只支持三种用法:- 传入迭代器(
iterator或const_iterator) - 传入
const key_type&(也就是你的Storage类型)
- 传入迭代器(
所以你的代码里find能跑,但erase("42")在C++20之前的标准下找不到对应的重载——编译器会尝试把const char[3]转成Storage,但你的Storage没有对应的构造函数,自然就报错了。
2. 快速解决:开启C++20编译
看你用g的报错信息,说明编译器没启用C20标准。你只需要在编译时加上C++20的参数:
g++ -std=c++20 your_code.cpp -o your_program
加上这个参数后,uset.erase("42")就能正常编译运行了,因为编译器会找到那个C++20新增的异构erase重载。
3. 兼容性替代方案(如果不能用C++20)
要是你因为项目限制没法升级到C20,完全可以用你已经写好的find逻辑间接删除,这种写法在C14及以上版本都能正常工作:
auto it = uset.find("42"); if (it != uset.end()) { uset.erase(it); // 用迭代器版本的erase,兼容性拉满 }
顺便夸一句:你的透明查找配置是对的
最后提一嘴,你给Storage写的透明哈希(带is_transparent)、三个operator==重载,还有使用std::equal_to<>作为比较器,这些都是异构查找的正确配置,只要标准版本支持,就能正常发挥作用~
内容来源于stack exchange
相关产品推荐
相关产品推荐

