I have a function which fills a container with random values between min and max using uniform distribution.
#include <iostream>
#include <random>
#include <algorithm>
#include <vector>
template<typename TContainer>
void uniform_random(TContainer& container,
const typename TContainer::value_type min,
const typename TContainer::value_type max) {
std::random_device rd;
std::mt19937 gen(rd());
// Below line does not work with integers container
std::uniform_real_distribution<typename TContainer::value_type> distribution(min, max);
auto lambda_norm_dist = [&](){ return distribution(gen); };
std::generate(container.begin(), container.end(), lambda_norm_dist);
}
int main() {
std::vector<float> a(10);
uniform_random(a,0,10);
for (auto el : a) { std::cout << el << " "; }
}
Replacing std::vector<float>
with std::vector<int>
does not work since I would have to use std::uniform_int_distribution
instead.
Is there a simple and elegant way to pick the right constructor depending on the value_type parameter ?
I was trying so far to use std::numeric_limits<typename TContainer::value_type>::is_integer
without success.
In C++14 (or C++11 with a minor change) you can create a uniform_distribution
type alias in this way:
template <typename ValueType>
using uniform_distribution = std::conditional_t<
std::is_floating_point<ValueType>::value,
std::uniform_real_distribution<ValueType>,
std::uniform_int_distribution<ValueType>
>;
Usage:
uniform_distribution<typename TContainer::value_type> distribution(min, max);
Write a meta-function select_distribution
which allows you to write this:
using value_type = typename TContainer::value_type;
using distribution_type = typename select_distribution<value_type>::type;
distribution_type distribution(min, max);
where select_distribution
is defined as:
template<typename T, bool = std::is_floating_point<T>::value>
struct select_distribution
{
using type = std::uniform_real_distribution<T>;
};
template<typename T>
struct select_distribution<T, false>
{
using type = std::uniform_int_distribution<T>;
};
Hope that helps.
One solution is to use a type trait helper and std::enable_if
:
template<class T, class Enable = void>
struct uniform_distribution_helper {};
template<class T>
struct uniform_distribution_helper<T, typename std::enable_if<std::is_floating_point<T>::value >::type> {
using type = std::uniform_real_distribution<T>;
};
template<class T>
struct uniform_distribution_helper<T, typename std::enable_if<std::is_integral<T>::value >::type> {
using type = std::uniform_int_distribution<T>;
};
Then in your function:
using uniform_distribution = typename uniform_distribution_helper<typename TContainer::value_type>::type;
// Below line does not work with integers container
uniform_distribution distribution(min, max);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With