C++ std::conditional的用法(附带实例)
C++ 中的 std::conditional 是一个类模板,它允许我们在编译时根据编译时布尔表达式在两种类型之间进行选择。
下面的示例展示了如何在编译时使用 std::conditional(和 std::conditional_t)在两种类型之间进行选择。
1) 在类型别名或 typedef 中,根据平台在 32 位和 64 位整数类型之间进行选择(指针大小在 32 位平台上为 4 字节,在 68 位平台上为 8 字节):
如果平台为 64 位,则条件的计算结果为 false,因为指针类型的大小为 8 字节,因此成员类型定义为 long long。
2) 在模板别名中,根据用户规范在 8 位、16 位、32 位或 64 位整数类型之间进行选择(作为非类型模板参数):
3) 在类型模板参数中,根据类型模板参数是整型还是浮点型在整数和实数均匀分布之间进行选择:
为了帮助简化 std::conditional 的用法,C++14 提供了一个模板别名 std::conditional_t。我们在这里的例子中看到过该模板,其定义如下:
下面的示例展示了如何在编译时使用 std::conditional(和 std::conditional_t)在两种类型之间进行选择。
1) 在类型别名或 typedef 中,根据平台在 32 位和 64 位整数类型之间进行选择(指针大小在 32 位平台上为 4 字节,在 68 位平台上为 8 字节):
using long_type = std::conditional_t<sizeof(void*) <= 4, long, long long>; auto n = long_type{42};如果平台是 32 位,那么指针类型的大小是 4 字节,因此编译时表达式 sizeof(void*)<=4 为 true,std::conditional 将其成员类型定义为 long。
如果平台为 64 位,则条件的计算结果为 false,因为指针类型的大小为 8 字节,因此成员类型定义为 long long。
2) 在模板别名中,根据用户规范在 8 位、16 位、32 位或 64 位整数类型之间进行选择(作为非类型模板参数):
template <int size> using number_type = typename std::conditional_t<size<=1, std::int8_t, typename std::conditional_t< size<=2, std::int16_t, typename std::conditional_t< size<=4, std::int32_t, std::int64_t> > >; auto n = number_type<2>{ 42 }; static_assert(sizeof(number_type<1>) == 1); static_assert(sizeof(number_type<2>) == 2); static_assert(sizeof(number_type<3>) == 4); static_assert(sizeof(number_type<4>) == 4); static_assert(sizeof(number_type<5>) == 8); static_assert(sizeof(number_type<6>) == 8); static_assert(sizeof(number_type<7>) == 8); static_assert(sizeof(number_type<8>) == 8); static_assert(sizeof(number_type<9>) == 8);实例中,std::conditional 被多次使用来模拟一系列 if...else 语句,以选择适当的类型。
3) 在类型模板参数中,根据类型模板参数是整型还是浮点型在整数和实数均匀分布之间进行选择:
template <typename T, typename D = std::conditional_t< std::is_integral_v<T>, std::uniform_int_distribution<T>, std::uniform_real_distribution<T>>, typename = typename std::enable_if_t< std::is_arithmetic_v<T>>> std::vector<T> GenerateRandom(T const min, T const max, size_t const size) { std::vector<T> v(size); std::random_device rd{}; std::mt19937 mt{ rd() }; D dist{ min, max }; std::generate(std::begin(v), std::end(v), [&dist, &mt] (return dist(mt); )); return v; } auto v1 = GenerateRandom(1, 10, 10); // integers auto v2 = GenerateRandom(1.0, 10.0, 10); // doubles我们使用模板别名 std::conditional_t 简化函数模板 Generate Random 的声明。这里,std::conditional 用于定义表示统计分布的类型模板参数的默认值。根据第一个类型模板参数 T 是整型还是浮点型,默认分布类型在 std::uniform_int_distribution<T> 和 std::uniform_real_distribution<T> 之间选择。通过使用 std::enable_if 和第三个模板参数来禁用其他类型的使用。
C++ std::conditional的工作原理
std::conditional 的类型转换特性是基于作为非类型模板参数提供的编译时常量布尔表达式完成的,它的实现如下所示:template<bool Test, class T1, class T2> struct conditional { typedef T2 type; }; template<class T1, class T2> struct conditional<true, T1, T2> { typedef T1 type; };
为了帮助简化 std::conditional 的用法,C++14 提供了一个模板别名 std::conditional_t。我们在这里的例子中看到过该模板,其定义如下:
template<bool Test, class T1, class T2> using conditional_t = typename conditional_t<Test,T1,T2>;这个辅助类(以及许多其他类似的辅助类和来自标准库的辅助类)是可选的,但它的使用有助于编写更简洁的代码。