#include <iostream>
#include <random>
#include <ctime>
#include <map>

struct Range
{
    int min;
    int max;
};

template <typename... T>
struct and_
    : std::true_type
{};

template <typename First, typename... Other>
struct and_<First, Other...>
    : std::integral_constant<bool, First::value && and_<Other...>::value>
{};

template < typename ...RangeT
         , typename = typename std::enable_if<
                    and_<
                        std::is_same<RangeT, Range>...
                    >::value
                >::type
>
int random(RangeT const &...args)
{
    static std::mt19937 mt(static_cast<unsigned>(time(nullptr)));
    auto gen = [](Range const & x, std::mt19937 & g)
    {
        return std::uniform_int_distribution<int>(x.min, x.max)(g);
    };
    int const values[] = { gen(args, mt)... };
    std::discrete_distribution<int> idx({ std::fabs(args.min - args.max)... });
    return values[idx(mt)];
}

int main()
{
    std::map<int, int> m;
    for(size_t n = 0; n < 10000; ++n)
    {
        ++m[random(Range{ 0, 2 }, Range{ 50, 100 })];
    }
    for(auto p : m)
    {
        std::cout << p.first << " generated " << p.second << " times\n";
    }
}