C++20如何通过concept正确校验自定义比较器的偏序约束
问题原因
你写的四个约束没有生效,核心原因是C++的requires表达式中,无后置类型约束的花括号语句仅检查表达式本身是否可以合法编译,完全不会校验表达式的求值结果是否为true。
你写的四个相等比较表达式,左右两边都是bool类型,==运算本身是合法可编译的,所以不管比较结果是true还是false,都会被requires判定为满足约束。哪怕你把逻辑写反,只要代码能编译,static_assert就会顺利通过。
核心认知纠正
首先要明确:C++ concept是编译期语法/类型层面的约束工具,没有能力直接校验任意运行时值的语义规则。你在requires参数列表里声明的t1、t2是完全抽象的形式参数,没有绑定任何实际取值,编译器不可能穷举T类型的所有可能值,去验证比较器对所有输入都满足偏序公理。
你想校验的四条对称规则:
t1 < t2等价于t2 > t1t2 < t1等价于t1 > t2t1 <= t2等价于t2 >= t1t2 <= t1等价于t1 >= t2
本质是三路比较器必须遵守的语义契约,不是靠concept就能100%静态校验的语法规则。对于返回std::partial_ordering的合法三路比较器,这些规则本身就是std::partial_ordering类型语义的一部分,正常实现的比较器都会默认遵守。
正确实现方式
通用的偏序比较器concept只需要做语法层面的约束即可,不需要也没法在concept层面覆盖所有语义校验:
#include <functional> #include <type_traits> #include <utility> #include <compare> template <typename F, typename T> concept PartiallyOrderedBy = requires(F&& f, const std::remove_reference_t<T>& t1, const std::remove_reference_t<T>& t2) { // 校验比较器可以被调用,返回值可转换为std::partial_ordering { std::invoke(std::forward<F>(f), t1, t2) } -> std::convertible_to<std::partial_ordering>; { std::invoke(std::forward<F>(f), t2, t1) } -> std::convertible_to<std::partial_ordering>; };
如果你确实需要对特定场景做静态语义校验,只能针对已知的编译期常量值做定向检查,这类检查属于特例校验,不能放到通用concept里约束所有类型。
注意:不要误以为在requires里加嵌套
requires子句就能强制校验表达式结果,这种方式只能对编译期常量生效,对于形式参数t1、t2这类没有实际值的符号,根本无法完成求值校验。
内容的提问来源于stack exchange,提问作者frozenca
相关产品推荐
相关产品推荐

