[英]Choose random number distribution at compile time
I am writing tests using the TYPED_TEST
feature of google tests, which allows me to generalize a test to multiple types. 我正在使用google测试的
TYPED_TEST
功能编写测试,这允许我将测试推广到多种类型。 I am testing a class template for the types int
and double
. 我正在测试类型
int
和double
的类模板。 In a test, I would need to generate random numbers. 在测试中,我需要生成随机数。 To do so, I have tried using the
std::uniform_int_distribution<T>
and the std::uniform_real_distribution<T>
but have ran into static asserts. 为此,我尝试使用
std::uniform_int_distribution<T>
和std::uniform_real_distribution<T>
但已经遇到静态断言。
As the names indicate, std::uniform_int_distribution<T>
checks if T
is an integral type and std::uniform_real_distribution<T>
checks that T
is a floating point type. 如名称所示,
std::uniform_int_distribution<T>
检查T
是否为整数类型, std::uniform_real_distribution<T>
检查T
是否为浮点类型。
Since my test automatically tests for int
and then for double
, I have been trying to write some kind of function that would allow me to chose the right kind of distribution for the type at compile time. 由于我的测试自动测试
int
然后为double
,我一直在尝试编写某种函数,这将允许我在编译时为类型选择正确的类型。 More precisely, something like: 更确切地说,类似于:
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);
}
}
Note that this is only a pseudocode of what I have been trying to do. 请注意,这只是我尝试做的伪代码。 This kind of logical branch fails because the
if
AND the else
have to compile. 这种逻辑分支失败,因为
if
和else
必须编译。
I have done some research on how to do this and I feel like std::is_integral<T>
and std::is_floating_point<T>
are part of the solution, but I have not been able to compile anything so far. 我已经做了一些研究如何做到这一点,我觉得
std::is_integral<T>
和std::is_floating_point<T>
是解决方案的一部分,但到目前为止我还没能编译任何东西。 I mainly tried two things: 我主要尝试了两件事:
enable_if
. enable_if
。 Using the first approach I ended up with an error message telling me my overloads were ambiguous. 使用第一种方法,我最终得到一条错误消息,告诉我我的重载是模棱两可的。 Using the second approach, I tried some stuff but got lost in the abominable syntax (at least for someone not used to it) which it lead to.
使用第二种方法,我尝试了一些东西,但却迷失了恶劣的语法(至少对于那些不习惯它的人来说)。
Do you have a suggestion on how this could be accomplished? 你有关于如何实现这一目标的建议吗?
PS I would like to see how this could be done, so splitting my test in two would not be an acceptable answer for me. PS我想知道如何做到这一点,所以将我的测试分成两部分对我来说不是一个可接受的答案。
I you may use C++17, you can make use of if constexpr(...)
: 我可以使用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";
}
For C++11 and C++14, you could use a conditional extra template type parameter in your template parameter list to select the return type as well as the distribution. 对于C ++ 11和C ++ 14,您可以在模板参数列表中使用条件额外模板类型参数来选择返回类型和分布。
C++11: 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 (return type deduced by auto
and using the std::conditional_t
helper type short form for std::conditional<...>::type
): 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);
}
I sometimes use std::conditional like this: 我有时会像这样使用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});
}
If you pass the function integer parameters it selects the int
distribution otherwise it selects the real
distribution. 如果传递函数整数参数,则选择
int
分布,否则选择real
分布。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.