在C++17引入的模板元编程工具中,std::conjunction和std::disjunction是用于编译期逻辑运算的类型工具,它们可以替代传统的递归模板逻辑判断,让代码更简洁易读。这两个类型定义在<type_traits>头文件中,主要作用是对一组类型特性进行逻辑与和逻辑或运算。
std::conjunction的定义与工作原理
std::conjunction的作用是对多个类型特性进行逻辑与运算,只有当所有传入的类型特性都为true时,它的value成员才为true,否则为false。它的实现基于短路求值规则,和运行时逻辑与运算符&&的行为一致。
它的基本定义形式如下:
#include <type_traits>
// 简化版实现示意,实际标准库实现更复杂
template <typename...>
struct conjunction : std::true_type {};
template <typename T>
struct conjunction<T> : T {};
template <typename T, typename... Ts>
struct conjunction<T, Ts...>
: std::conditional<bool(T::value), conjunction<Ts...>, T>::type {};
从实现可以看出,当第一个类型特性的value为false时,就不会再计算后续的类型特性,直接返回false,这就是短路求值的体现。
std::disjunction的定义与工作原理
std::disjunction的作用是对多个类型特性进行逻辑或运算,只要有一个传入的类型特性为true,它的value成员就为true,只有所有都为false时才为false。它同样支持短路求值,和运行时逻辑或运算符||的行为一致。
简化版实现示意如下:
#include <type_traits>
template <typename...>
struct disjunction : std::false_type {};
template <typename T>
struct disjunction<T> : T {};
template <typename T, typename... Ts>
struct disjunction<T, Ts...>
: std::conditional<bool(T::value), T, disjunction<Ts...>>::type {};
当第一个类型特性的value为true时,就不会再计算后续的类型特性,直接返回true。
使用场景与代码示例
多类型特性判断
假设我们需要判断一个类型是否同时满足是整型、有符号、不是长整型三个条件,使用std::conjunction可以很简洁地实现:
#include <iostream>
#include <type_traits>
#include <string>
int main() {
// 判断int是否同时满足三个条件
bool result1 = std::conjunction<
std::is_integral<int>,
std::is_signed<int>,
std::negation<std::is_same<int, long>>
>::value;
std::cout << "int是否符合条件: " << result1 << std::endl; // 输出1
// 判断long是否满足条件
bool result2 = std::conjunction<
std::is_integral<long>,
std::is_signed<long>,
std::negation<std::is_same<long, long>> // 这里会为false
>::value;
std::cout << "long是否符合条件: " << result2 << std::endl; // 输出0
return 0;
}
逻辑或判断场景
如果需要判断一个类型是否是整型或者浮点型,使用std::disjunction实现:
#include <iostream>
#include <type_traits>
int main() {
// 判断int是否是整型或浮点型
bool result1 = std::disjunction<
std::is_integral<int>,
std::is_floating_point<int>
>::value;
std::cout << "int是否是整型或浮点型: " << result1 << std::endl; // 输出1
// 判断std::string是否是整型或浮点型
bool result2 = std::disjunction<
std::is_integral<std::string>,
std::is_floating_point<std::string>
>::value;
std::cout << "std::string是否是整型或浮点型: " << result2 << std::endl; // 输出0
return 0;
}
和传统模板逻辑判断的对比
在C++17之前,要实现多个类型特性的逻辑与判断,通常需要写递归模板,代码冗长且可读性差。例如实现逻辑与判断的传统方式:
#include <type_traits>
// 传统递归模板实现逻辑与
template <typename...>
struct old_conjunction : std::true_type {};
template <typename T>
struct old_conjunction<T> : T {};
template <typename T, typename... Ts>
struct old_conjunction<T, Ts...> {
static constexpr bool value = T::value && old_conjunction<Ts...>::value;
};
对比可见,std::conjunction是标准库已经实现好的工具,不需要开发者自己重复编写递归模板,减少了出错概率,也让代码更符合标准规范。
注意事项
- std::conjunction和std::disjunction的模板参数必须是具有
value成员的类型,通常是类型特性类。 - 它们的结果是编译期常量,可以用于模板参数、
if constexpr等编译期判断场景。 - 短路求值特性可以避免不必要的类型计算,比如某个类型特性的计算本身有副作用或者成本较高时,这个特性会很有用。
std::conjunctionstd::disjunctionC++17模板元编程修改时间:2026-06-20 22:15:33