[英]Choose random number distribution at compile time
我正在使用google测试的TYPED_TEST
功能编写测试,这允许我将测试推广到多种类型。 我正在测试类型int
和double
的类模板。 在测试中,我需要生成随机数。 为此,我尝试使用std::uniform_int_distribution<T>
和std::uniform_real_distribution<T>
但已经遇到静态断言。
如名称所示, std::uniform_int_distribution<T>
检查T
是否为整数类型, std::uniform_real_distribution<T>
检查T
是否为浮点类型。
由于我的测试自动测试int
然后为double
,我一直在尝试编写某种函数,这将允许我在编译时为类型选择正确的类型。 更确切地说,类似于:
template<class T>
Distribution get_right_distribution(const T& a, const T& b)
{
if(T is integral) // Compile time is needed, runtime
// fails since both if and else have to compile
{
return std::uniform_real_distribution(a, b);
}
else
{
return std::uniform_real_distribution(a, b);
}
}
请注意,这只是我尝试做的伪代码。 这种逻辑分支失败,因为if
和else
必须编译。
我已经做了一些研究如何做到这一点,我觉得std::is_integral<T>
和std::is_floating_point<T>
是解决方案的一部分,但到目前为止我还没能编译任何东西。 我主要尝试了两件事:
enable_if
。 使用第一种方法,我最终得到一条错误消息,告诉我我的重载是模棱两可的。 使用第二种方法,我尝试了一些东西,但却迷失了恶劣的语法(至少对于那些不习惯它的人来说)。
你有关于如何实现这一目标的建议吗?
PS我想知道如何做到这一点,所以将我的测试分成两部分对我来说不是一个可接受的答案。
我可以使用C ++ 17,你可以使用if constexpr(...)
:
#include <iostream>
#include <random>
#include <type_traits>
template <typename T>
auto get_right_distribution(const T a, const T b) {
if constexpr(std::is_integral<T>::value) {
return std::uniform_int_distribution(a, b);
}
else {
return std::uniform_real_distribution(a, b);
}
}
int main() {
std::random_device rd;
std::mt19937 gen(rd());
auto int_dis = get_right_distribution(1, 6);
std::cout << int_dis(gen) << "\n";
auto float_dis = get_right_distribution(1.F, 6.F);
std::cout << float_dis(gen) << "\n";
}
对于C ++ 11和C ++ 14,您可以在模板参数列表中使用条件额外模板类型参数来选择返回类型和分布。
C ++ 11:
template <typename T,
typename Distribution = typename std::conditional<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>>::type>
Distribution get_right_distribution(const T a, const T b) {
return Distribution(a, b);
}
C ++ 14(由auto
推导的返回类型,并使用std::conditional<...>::type
的std::conditional_t
helper类型的短格式):
template <typename T,
typename Distribution = typename std::conditional_t<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>>>
auto get_right_distribution(const T a, const T b) {
return Distribution(a, b);
}
我有时会像这样使用std :: conditional :
template<typename Number>
Number random_number(Number from, Number to)
{
static_assert(std::is_integral<Number>::value
|| std::is_floating_point<Number>::value,
"parameters must be integer or floating point types");
using Distribution = typename std::conditional
<
std::is_integral<Number>::value,
std::uniform_int_distribution<Number>,
std::uniform_real_distribution<Number>
>::type;
// in reality I usually get the generator from another
// function, but for many purposes this is fine.
thread_local static std::mt19937 mt{std::random_device{}()};
thread_local static Distribution dist;
return dist(mt, typename Distribution::param_type{from, to});
}
如果传递函数整数参数,则选择int
分布,否则选择real
分布。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.