如何根据数值类型自动选择标准库中的均匀分布模板?
问题
给定数值类型T,能否根据T是整数类型还是浮点类型,简洁地将变量声明为std::uniform_int_distribution<T>或std::uniform_real_distribution<T>?
为生成在调用者定义范围内均匀分布的随机std::chrono::duration,我实现了模仿标准库分布类模板的uniform_duration_distribution类模板,先定义chrono_duration概念约束类型。但因duration的rep类型可能是整数或浮点,无法直接使用不存在的std::uniform_distribution<T>。
我尝试用概念约束的类型别名模板选择分布类型,但该方式不被允许,且无法特化类型别名模板。最终通过结构体模板特化实现类型选择,想了解是否有更现代的C++方法。
解决方案
下面是几种更简洁的现代C++实现方式:
1. 利用std::conditional_t与类型特性
通过std::is_integral_v判断rep类型的特性,配合std::conditional_t直接在类模板中选择对应的分布类型,无需额外结构体:
#include <random> #include <type_traits> #include <chrono> template<typename Rep, typename Period> class uniform_duration_distribution { // 根据Rep的类型自动选择分布 using DistType = std::conditional_t< std::is_integral_v<Rep>, std::uniform_int_distribution<Rep>, std::uniform_real_distribution<Rep> >; DistType dist_; public: explicit uniform_duration_distribution(const std::chrono::duration<Rep, Period>& min, const std::chrono::duration<Rep, Period>& max) : dist_(min.count(), max.count()) {} template<typename URBG> auto operator()(URBG& rng) { return std::chrono::duration<Rep, Period>(dist_(rng)); } };
2. C++20概念约束的别名模板(合法实现)
你之前的思路是可行的,只是写法有误——C++20允许为同一个别名模板定义多个带互斥约束的声明,而非特化:
#include <random> #include <concepts> #include <chrono> // 针对整数类型的分布别名 template<std::integral T> using uniform_distribution = std::uniform_int_distribution<T>; // 针对浮点类型的分布别名 template<std::floating_point T> using uniform_distribution = std::uniform_real_distribution<T>; template<typename Rep, typename Period> class uniform_duration_distribution { using DistType = uniform_distribution<Rep>; DistType dist_; public: explicit uniform_duration_distribution(const std::chrono::duration<Rep, Period>& min, const std::chrono::duration<Rep, Period>& max) : dist_(min.count(), max.count()) {} template<typename URBG> auto operator()(URBG& rng) { return std::chrono::duration<Rep, Period>(dist_(rng)); } };
这里std::integral和std::floating_point是互斥概念,编译器能准确匹配到对应的分布类型。
3. C++20 constexpr if(函数内直接分支)
如果是在函数中生成随机时长,用constexpr if可以直接在编译时选择分布类型,代码更直观:
#include <random> #include <type_traits> #include <chrono> template<typename Rep, typename Period, typename URBG> auto generate_random_duration(URBG& rng, const std::chrono::duration<Rep, Period>& min, const std::chrono::duration<Rep, Period>& max) { if constexpr (std::is_integral_v<Rep>) { std::uniform_int_distribution<Rep> dist(min.count(), max.count()); return std::chrono::duration<Rep, Period>(dist(rng)); } else { std::uniform_real_distribution<Rep> dist(min.count(), max.count()); return std::chrono::duration<Rep, Period>(dist(rng)); } }
内容的提问来源于stack exchange,提问作者Adrian McCarthy
相关产品推荐
相关产品推荐

