C++20中如何用Concept检查含std::shared_ptr的重载<=>运算符
问题根源分析与解决方案
大概率是你的Concept定义未覆盖「类与std::shared_ptr<T>跨类型比较」的场景,或是重载的<=>运算符存在const正确性、参数顺序的问题,以下分常见情况逐一说明:
1. Concept仅检查同类型比较,未覆盖跨类型场景
假设你的Concept是类似这样的:
#include <compare> #include <memory> template<typename T> concept Sortable = requires(const T& a, const T& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; };
它只验证了同类型T之间的比较,但你的类实际重载的是和std::shared_ptr<T>的跨类型<=>,自然无法满足Concept的检查条件。
若需要Sortable支持「T与shared_ptr<T>的双向比较」,需修改Concept,同时覆盖两种方向的比较逻辑:
template<typename T> concept Sortable = // 保留同类型比较(如果业务需要) requires(const T& a, const T& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; } // 支持T与shared_ptr<T>的比较(左值为T) && requires(const T& a, const std::shared_ptr<T>& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; } // 支持shared_ptr<T>与T的比较(左值为shared_ptr<T>) && requires(const std::shared_ptr<T>& a, const T& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; };
2. 重载的<=>运算符存在const正确性问题
如果你的类的<=>重载没有加const修饰,比如:
class MySortableElement { int value; public: // 错误:缺少const,无法在const T&的上下文中调用 std::strong_ordering operator<=>(const std::shared_ptr<MySortableElement>& other) { return value <=> other->value; } };
而Concept中使用了const T&作为参数,编译器会判定该运算符不可用,导致Concept不满足。必须给运算符加上const:
std::strong_ordering operator<=>(const std::shared_ptr<MySortableElement>& other) const { return value <=> other->value; }
3. 未处理shared_ptr为空的边界情况(可选但重要)
虽然这不是Concept不通过的直接原因,但如果你的<=>重载直接访问other->value,当other为空时会触发未定义行为。建议补充空指针处理逻辑:
std::strong_ordering operator<=>(const std::shared_ptr<MySortableElement>& other) const { if (!other) { // 可约定空指针小于任何非空对象,或根据业务调整规则 return std::strong_ordering::greater; } return value <=> other->value; }
验证示例
修改后的完整可运行代码:
#include <compare> #include <memory> template<typename T> concept Sortable = requires(const T& a, const T& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; } && requires(const T& a, const std::shared_ptr<T>& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; } && requires(const std::shared_ptr<T>& a, const T& b) { { a <=> b } -> std::convertible_to<std::strong_ordering>; }; class MySortableElement { int value; public: MySortableElement(int v) : value(v) {} std::strong_ordering operator<=>(const MySortableElement& other) const { return value <=> other.value; } std::strong_ordering operator<=>(const std::shared_ptr<MySortableElement>& other) const { if (!other) return std::strong_ordering::greater; return value <=> other->value; } // 支持shared_ptr<T> <=> T的反向比较,复用已有逻辑自动反转结果 friend std::strong_ordering operator<=>(const std::shared_ptr<MySortableElement>& lhs, const MySortableElement& rhs) { return rhs <=> lhs; } }; template<Sortable T> class SortableList {}; // 现在可正常实例化 SortableList<MySortableElement> list;
内容的提问来源于stack exchange,提问作者JuliusCaesar
相关产品推荐
相关产品推荐

