使用Lambda作为自定义比较器创建集合时报错:尝试引用已删除函数
错误含义解释
这个报错的核心是:你试图调用一个被编译器删除的函数——也就是你定义的lambda表达式的闭包类型的默认构造函数。
在C11到C17标准中,lambda生成的闭包类型默认没有默认构造函数(C++20开始,无捕获的lambda才允许默认构造,但旧标准不支持)。当你用decltype(comparator)作为set的比较器类型时,这个类型就是lambda的闭包类型,而后续代码中(比如用H[key]访问不存在的键时),unordered_map会尝试默认构造一个set对象,而set的默认构造函数需要默认构造它的比较器——也就是你的lambda闭包,但这个闭包的默认构造函数已经被删除了,所以编译器抛出了这个错误。
你的代码问题
核心问题是:将lambda闭包类型直接作为set的比较器类型,而lambda闭包无法被默认构造,但unordered_map在创建新的set元素时(比如通过operator[])必须调用set的默认构造函数,这就触发了矛盾。
解决方案
最稳妥且简洁的方案是把lambda换成自定义的结构体比较器,这样可以完全避开lambda闭包的构造限制:
// 定义一个带operator()的结构体作为比较器 struct PairComparator { bool operator()(const pair<int, int>& a, const pair<int, int>& b) const { return a.second == b.second ? a.first < b.first : a.second < b.second; } }; // 直接使用结构体作为set的比较器类型 unordered_map<int, set<pair<int, int>, PairComparator>> H;
这个方案的优势很明显:
- 结构体的默认构造函数是编译器自动生成的,
set可以正常默认构造,unordered_map的operator[]也能正常工作 - 代码可读性更高,符合C++的常规写法
- 没有额外的性能开销(不像
std::function会有轻微的间接调用开销)
如果你坚持想用lambda,也可以用std::function包装它,但需要注意必须显式初始化每个set的比较器,避免默认构造空的std::function导致运行时崩溃:
#include <functional> // 必须包含这个头文件 using ComparatorFunc = function<bool(const pair<int, int>&, const pair<int, int>&)>; auto comparator = [](const pair<int, int>& a, const pair<int, int>& b) { return a.second == b.second ? a.first < b.first : a.second < b.second; }; unordered_map<int, set<pair<int, int>, ComparatorFunc>> H; // 插入元素时必须显式构造带比较器的set H.emplace(123, set<pair<int, int>, ComparatorFunc>(comparator));
不过这种写法不如结构体方案简洁,还有一定的运行时开销,所以更推荐前者。
内容的提问来源于stack exchange,提问作者Eduard Rostomyan
相关产品推荐
相关产品推荐

