You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设计兼容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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:56:15