如何设计兼容std::queue与std::priority_queue的C++模板?C++17编译问题
C++17下ThreadSafePriorityQueue编译错误原因及修复方案
原代码示例
模板定义
template<typename T, typename QueueType = std::queue<std::shared_ptr<T>>> class ThreadSafeQueue {}; template<typename T> auto cmp = [](const T& d1, const T& d2) { return d1 > d2; }; template<typename T> using ThreadSafePriorityQueue = ThreadSafeQueue<T, std::priority_queue<std::shared_ptr<T>, std::vector<std::shared_ptr<T>>, decltype(cmp<std::shared_ptr<T>>)>>;
测试代码
struct S { bool operator>(const S& other) const { return false; } }; ThreadSafeQueue<S> q; ThreadSafePriorityQueue<S> q1;
错误原因
C++17标准中,lambda表达式的闭包类型没有默认构造函数,且该类型的默认构造函数被显式删除。当你用decltype(cmp<std::shared_ptr<T>>)作为std::priority_queue的比较器类型时,priority_queue会尝试默认构造这个比较器实例,但由于闭包类型的默认构造函数不可用,编译器会抛出error C2280(尝试引用已删除的函数)。
而C20标准放宽了限制:无捕获的lambda闭包类型允许默认构造,因此代码在C20下可以正常编译。
C++17下的修改方案
方案1:用函数模板替代lambda
将lambda替换为普通的函数模板,此时比较器类型为函数指针,支持默认构造:
template<typename T, typename QueueType = std::queue<std::shared_ptr<T>>> class ThreadSafeQueue {}; // 替换lambda为函数模板 template<typename T> bool cmp(const T& d1, const T& d2) { return d1 > d2; } template<typename T> using ThreadSafePriorityQueue = ThreadSafeQueue<T, std::priority_queue<std::shared_ptr<T>, std::vector<std::shared_ptr<T>>, // 指定函数指针类型,或用decltype(&cmp<std::shared_ptr<T>>) bool(*)(const std::shared_ptr<T>&, const std::shared_ptr<T>&)>>;
方案2:用仿函数类替代lambda
自定义一个带operator()的模板类,仿函数类天然支持默认构造:
template<typename T, typename QueueType = std::queue<std::shared_ptr<T>>> class ThreadSafeQueue {}; // 定义仿函数模板 template<typename T> struct Cmp { bool operator()(const T& d1, const T& d2) const { return d1 > d2; } }; template<typename T> using ThreadSafePriorityQueue = ThreadSafeQueue<T, std::priority_queue<std::shared_ptr<T>, std::vector<std::shared_ptr<T>>, Cmp<std::shared_ptr<T>>>>;
方案3:绑定lambda实例(需调整ThreadSafeQueue构造逻辑)
如果坚持使用lambda,可以将cmp定义为constexpr模板变量,并在创建priority_queue时传入该实例。但这需要修改ThreadSafeQueue的构造函数,让它能接收比较器参数:
#include <memory> #include <queue> #include <vector> template<typename T, typename QueueType = std::queue<std::shared_ptr<T>>> class ThreadSafeQueue { public: // 新增构造函数,接收QueueType的构造参数 template<typename... Args> ThreadSafeQueue(Args&&... args) : queue(std::forward<Args>(args)...) {} private: QueueType queue; }; template<typename T> constexpr auto cmp = [](const T& d1, const T& d2) { return d1 > d2; }; template<typename T> using ThreadSafePriorityQueue = ThreadSafeQueue<T, std::priority_queue<std::shared_ptr<T>, std::vector<std::shared_ptr<T>>, decltype(cmp<std::shared_ptr<T>>)>>; // 调用时传入lambda实例 int main() { struct S { bool operator>(const S& other) const { return false; } }; ThreadSafeQueue<S> q; // 传入cmp<std::shared_ptr<S>>作为比较器 ThreadSafePriorityQueue<S> q1(cmp<std::shared_ptr<S>>); return 0; }
内容的提问来源于stack exchange,提问作者f1msch
相关产品推荐
相关产品推荐

