如何根据类型是否支持<运算符选择std::queue或std::priority_queue?
可行实现方案
方案1:C++17及更早版本(基于void_t和SFINAE)
首先需要正确实现类型特性来检测F是否支持<运算符,再通过SFINAE隔离两个分支的实例化:
#include <queue> #include <utility> #include <type_traits> // 基础模板,默认标记为不支持< template <typename T, typename = void> struct has_less : std::false_type {}; // 当T支持a < b时,匹配此特化 template <typename T> struct has_less<T, std::void_t<decltype(std::declval<T>() < std::declval<T>())>> : std::true_type {}; // 辅助变量模板,简化使用 template <typename T> constexpr bool has_less_v = has_less<T>::value; // 分情况定义QueueImpl template <typename F, typename S, bool = has_less_v<F>> struct QueueImpl; // 支持<的分支:使用priority_queue template <typename F, typename S> struct QueueImpl<F, S, true> { using type = std::priority_queue<std::pair<F, S>>; }; // 不支持<的分支:使用queue template <typename F, typename S> struct QueueImpl<F, S, false> { using type = std::queue<std::pair<F, S>>; }; // 最终别名 template <typename F, typename S> using Queue = typename QueueImpl<F, S>::type;
方案优势
has_less特性能准确在编译期判断F的<运算符支持情况,解决了之前SFINAE条件错误导致的匹配问题。- 两个
QueueImpl特化互斥,仅符合条件的分支会被实例化,不会像std::conditional那样触发未选中分支的编译错误。
方案2:C++20及以上版本(基于Concepts)
利用C++20的Concepts可以写出更简洁直观的实现:
#include <queue> #include <utility> // 定义Concept:检测类型是否支持<运算符 template <typename T> concept LessComparable = requires(T a, T b) { { a < b } -> std::convertible_to<bool>; }; // 结合conditional_t和Concept实现分支选择 template <typename F, typename S> using Queue = std::conditional_t<LessComparable<F>, std::priority_queue<std::pair<F, S>>, std::queue<std::pair<F, S>>>;
方案优势
- C++20中
std::conditional_t配合Concept使用时,编译器只会实例化选中的分支,避免了无效分支的编译错误。 - 代码结构更简洁,可读性更高,无需额外编写类型特性模板。
测试示例
// 支持<的类型 struct A { int val; bool operator<(const A& other) const { return val < other.val; } }; // 不支持<的类型 struct C {}; int main() { // Queue<A, int> 对应std::priority_queue<std::pair<A, int>> Queue<A, int> pq; pq.push({A{1}, 100}); // Queue<C, int> 对应std::queue<std::pair<C, int>> Queue<C, int> q; q.push({C{}, 200}); return 0; }
关键注意点
- 若之前的SFINAE实现总是匹配
std::queue分支,大概率是类型检测条件写得有误,比如未正确使用declval或void_t,上述has_less是标准的正确写法。 - 禁止直接使用无分支隔离的
std::conditional,否则会因实例化无效分支触发编译错误。
内容的提问来源于stack exchange,提问作者Ziyuan
相关产品推荐
相关产品推荐

