在编译时选择随机数分布 [英] Choose random number distribution at compile time

查看:98
本文介绍了在编译时选择随机数分布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Google测试的TYPED_TEST功能编写测试,这使我可以将测试归纳为多种类型.我正在测试类型intdouble的类模板.在测试中,我需要生成随机数.为此,我尝试使用std::uniform_int_distribution<T>std::uniform_real_distribution<T>,但是遇到了静态断言.

I am writing tests using the TYPED_TEST feature of google tests, which allows me to generalize a test to multiple types. I am testing a class template for the types int and 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> 检查T是否为整数类型,并且 std::uniform_real_distribution<T> 检查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.

由于我的测试会先自动测试int,然后再测试double,所以我一直在尝试编写某种函数,该函数可让我在编译时为该类型选择正确的分布.更准确地说,是这样的:

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. 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);
    }
}

请注意,这只是我一直在尝试的操作的伪代码.这种逻辑分支失败,因为ifelse必须编译.

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.

我已经对如何执行此操作进行了一些研究,我觉得std::is_integral<T>std::is_floating_point<T>是解决方案的一部分,但是到目前为止我还不能编译任何东西.我主要尝试了两件事:

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. I mainly tried two things:

  1. 使用模板专门化来进行某种编译.
  2. 使用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.

您对此有何建议?

P.S.我想看看如何做到这一点,所以将测试一分为二对我来说不是一个可以接受的答案.

P.S. I would like to see how this could be done, so splitting my test in two would not be an acceptable answer for me.

推荐答案

C ++ 17

我可以使用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和C ++ 14,您可以在模板参数列表中使用条件附加模板类型参数来选择返回类型和分布.

C++11 & C++14

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:

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辅助类型缩写形式的返回类型):

C++ 14 (return type deduced by auto and using the std::conditional_t helper type short form for std::conditional<...>::type):

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);
}

这篇关于在编译时选择随机数分布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆