使用lambda为比较器的std::map嵌套std::priority_queue编译问题分析与解决
问题原因分析与修改方案
编译失败的核心原因
- 你错误地把给
Person用的lambda传给了std::map的构造函数。std::map构造时传入的比较器是用于**排序键(也就是std::string)**的,而你传入的MyComparator只能比较两个Person,类型完全不匹配,这是最直接的编译报错来源。 - 第二点,
decltype(MyComparator)也就是lambda的类型,在C++20之前是没有默认构造函数的。而std::priority_queue默认构造时需要自动生成比较器实例,lambda类型无法完成默认构造,后续如果用到map的operator[](自动插入默认值的场景),会直接编译失败。
结构体比较器可运行的原因
你写的MyComparator结构体(或公有operator()的类)是可默认构造的:没有成员变量,编译器自动生成无参构造函数,不需要手动传参就能生成实例。
- 作为
priority_queue的比较器模板参数时,默认构造priority_queue会自动调用MyComparator的无参构造生成比较器实例,完全不需要额外手动传参。 std::map本身的键是std::string,直接用默认的std::less<std::string>排序,不需要传任何构造参数,因此代码可以直接编译运行。
代码修改方案
根据你使用的C++版本分两种情况处理:
通用方案(兼容C++11及以上所有版本)
不要给std::map传MyComparator,插入元素时显式给priority_queue传入lambda实例即可,建议用类型别名简化写法:
auto MyComparator = [](const Person &a, const Person &b) { return a.YearOfBirth > b.YearOfBirth; }; // 给自定义比较的优先队列起别名,简化后续写法 using PersonPriorityQueue = std::priority_queue<Person, std::vector<Person>, decltype(MyComparator)>; // map构造不需要传任何参数,键是string用默认比较器即可 std::map<std::string, PersonPriorityQueue> Familly; // 插入元素时,显式给优先队列传入比较器实例 Familly.emplace("家庭成员组1", PersonPriorityQueue(MyComparator));
注意:这个方案下不能直接用
Familly["xxx"]的写法,因为operator[]会默认构造PersonPriorityQueue,而C++20之前lambda类型无法默认构造比较器。
C++20及以上版本简化方案
C++20为无捕获lambda新增了默认构造函数,此时decltype(MyComparator)是可默认构造的,直接声明即可正常使用,甚至可以直接用operator[]:
auto MyComparator = [](const Person &a, const Person &b) { return a.YearOfBirth > b.YearOfBirth; }; std::map<std::string, std::priority_queue<Person, std::vector<Person>, decltype(MyComparator)>> Familly; // 可以直接用operator[]自动插入默认构造的优先队列 Familly["家庭成员组1"].push(Person{});
内容的提问来源于stack exchange,提问作者40tude
相关产品推荐
相关产品推荐

