std::disjunction 是编译期类型计算工具,必须用于 requires 表达式或 static_assert 中,参数须为继承自 std::integral_constant 的类型特征类(如 std::is_integral),不可用 _v 版本或值类型;使用时需配合 ::value 或 _v 别名(如 std::disjunction_v)以满足 concept 对布尔常量表达式的要求。

std::disjunction 在 C++20 模板约束里怎么写才不报错
它不是运行时函数,不能直接调用;它是编译期类型计算工具,必须用在 requires 表达式或 static_assert 里,否则会触发 SFINAE 失败或硬错误。
-
std::disjunction接收的是类型模板参数(比如std::is_integral_v<t></t>是值,不能直接塞进去;得用std::is_integral<t></t>) - 常见误写:
std::disjunction<:is_integral_v>></:is_integral_v>→ 错,_v版本是布尔值,不是类型 - 正确写法:
std::disjunction<:is_integral>, std::is_enum<t>></t></:is_integral>,每个参数都必须是带::value的类型特征类(即继承自std::integral_constant的类型) - 如果混入非类型(比如
bool字面量),编译器通常报template argument 1 is invalid或类似no type named 'type'
和 requires (A || B) 直接写逻辑或有啥区别
本质一样,但语义和错误提示不同:直接写 requires std::is_integral_v<t> || std::is_enum_v<t></t></t> 更简洁,而 std::disjunction 主要用于需要“延迟求值”或组合已有 trait 类型的场景。
- 直接
||在requires中可读性高,编译器报错时通常能准确定位哪个子句失败 -
std::disjunction必须配合::value使用,比如requires std::disjunction_v<:is_integral>, std::is_enum<t>></t></:is_integral>(注意_v后缀) - 如果你封装了一个复合 trait,比如
template<typename t> using is_arith_or_enum = std::disjunction<:is_arithmetic>, std::is_enum<t>></t></:is_arithmetic></typename>,那复用性比重复写||更干净 - 性能无差异 —— 全是编译期计算,生成的代码完全一致
为什么有时候 std::disjunction_v 编译不过,但 std::conjunction_v 可以
不是实现问题,而是你传进去的类型里有“未定义行为”的 trait 实例 —— 比如对 void、引用、数组等非法类型做 std::is_class,在 std::disjunction 中可能提前触发实例化失败。
-
std::disjunction是短路逻辑,但 C++ 模板实例化不保证短路:所有模板实参仍会被检查是否有效类型 - 典型翻车点:
std::disjunction<:is_class>, std::is_integral<t>></t></:is_class>遇到T = void时,std::is_class<void></void>合法,但std::is_integral<void></void>是 ill-formed,整个表达式失败 - 解决办法:先用
std::is_valid(C++20std::is_detected替代方案)包裹,或改用requires+||让约束本身参与 SFINAE - 简单验证:把每个 trait 单独放进
static_assert看是否崩,就能定位哪个类型不兼容
在 concept 定义里用 std::disjunction 容易漏掉什么
容易忽略 std::disjunction 返回的是类型,不是布尔值;concept 要求的是布尔常量表达式,所以必须取 ::value 或用 _v 别名。
立即学习“C++免费学习笔记(深入)”;
- 错:
concept ArithOrPtr = std::disjunction<:is_arithmetic>, std::is_pointer<t>>;</t></:is_arithmetic>→ 缺少::value,编译器报concept definition requires a boolean constant expression - 对:
concept ArithOrPtr = std::disjunction_v<:is_arithmetic>, std::is_pointer<t>>;</t></:is_arithmetic> - 更安全写法:用
requires显式展开,避免嵌套过深导致错误信息模糊,例如:concept ArithOrPtr = requires(T t) { requires std::is_arithmetic_v<t> || std::is_pointer_v<t>; };</t></t> - 别依赖 IDE 的自动补全——有些老版本 clangd 会把
std::disjunction当成函数建议,补全成括号调用,一粘贴就红
std::is_* 在捣鬼。宁可多拆几个小 concept,也别一股脑塞进一个 std::disjunction。








