Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Template function for random number generation (static assertion failed)

I created a simple template function to generate a random number of type T (I need int or float) in range [low, high) as follows:

template <typename T>
T randm(T low, T high)
{
    static std::random_device seeder;
    static std::mt19937 gen(seeder());
    std::uniform_real_distribution<T> dis(low, high);
    return dis(gen);
}

However when I try to call it as:

int r = randm<int>(0, 10);

I get the error: "static assertion failed: result_type must be a floating point type".

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I found out that if I use uniform_real_distribution<> instead of uniform_real_distribution<T>, it works, but I am not sure why (and if I am not mistaken uniform_real_distribution<> defaults to double which I don’t need).

>Solution :

For integral types, there is std::uniform_int_distribution. You have to apply something with if constexpr or to use SFNIAE (with type traits) to handle floating points and integrals separately. Btw. there is a note in std::uniform_real_distribution: The effect is undefined if this is not one of float, double, or long double. ("this" concerns the template type.)

Two separate functions distinguished by SFINAE:

#include <iostream>
#include <random>

template <typename T,
  std::enable_if_t<std::is_integral_v<T>, int> = 0
>
T randm(T low, T high)
{
    static std::random_device seeder;
    static std::mt19937 gen(seeder());
    std::uniform_int_distribution<T> dis(low, high);
    return dis(gen);
}

template <typename T,
  std::enable_if_t<std::is_floating_point_v<T>, int> = 0
>
T randm(T low, T high)
{
    static std::random_device seeder;
    static std::mt19937 gen(seeder());
    std::uniform_real_distribution<T> dis(low, high);
    return dis(gen);
}

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  DEBUG(std::cout << randm(0, 10) << std::endl);
  DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}

Output:

std::cout << randm(0, 10) << std::endl;
4
std::cout << randm(0.0f, 10.0f) << std::endl;
9.05245

Live Demo on coliru

Using if constexpr (requires at least C++17):

#include <iostream>
#include <random>

template <typename T>
T randm(T low, T high)
{
  static std::random_device seeder;
  static std::mt19937 gen(seeder());
  if constexpr (std::is_integral_v<T>) {
    std::uniform_int_distribution<T> dis(low, high);
    return dis(gen);
  }
  if constexpr (std::is_floating_point_v<T>) {
    std::uniform_real_distribution<T> dis(low, high);
    return dis(gen);
  }
  return T(); // ERROR?
}

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  DEBUG(std::cout << randm(0, 10) << std::endl);
  DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}

Output:

std::cout << randm(0, 10) << std::endl;
7
std::cout << randm(0.0f, 10.0f) << std::endl;
3.51174

Live Demo on coliru

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading