C++ Random Number Generation
That seems like a lot of code for very little purpose. It's allowing you to write

IntRandom&lt;int&gt; r(17, 42);
int i = r.Next();


instead of the no-helpers version,

std::mt19937 g(std::random_device{}());
std::uniform_int_distribution&lt;int&gt; dist(17, 42);
int i = dist(g);


Some people would say that that's not worth the 77 lines of code.



Two small problems with your code, related to your use of random_device: First, you're using only 32 bits of entropy to seed your entire Mersenne Twister; it would be better to use as many bits as the mt19937 has bits of state. However, doing this correctly is needlessly difficult in C++17, so you get a pass on it for now.

Second, your RandomBase class keeps a member of type random_device. This might be problematic, because a random_device is essentially an open file handle to /dev/urandom. If you create a lot of RandomBase objects at once, you might find yourself running out of file handles.

Oh, and a third problem is that random_device is non-copyable and non-movable; so your RandomBase is also non-movable. That could actually be pretty bad, depending on how you want to use it.



You could fix the random_device issues by removing the random_device data member, and instead providing a method like this:

void RandomBase::reseed() {
    std::random_device rd;
    m_RandomGenerator.seed(rd());  // TODO: better seeding
}


This keeps the random_device alive (and /dev/urandom open) only as long as it's needed; and it removes the data member from the class so that the class becomes movable and even copyable.



You could also reduce duplication by using templates and type-aliases, something like this:

template&lt;class Distribution&gt;
class dist_and_gen {
    std::mt19937 m_g;
    Distribution m_dist;

    template&lt;class... Args&gt;
    explicit constexpr dist_and_gen(Args&amp;&amp;...) :
        m_dist(std::forward&lt;Args&gt;(args)...) {}

    auto next() { return m_dist(m_g); }
    auto params() const { return m_dist.params(); }
};

template&lt;class T&gt; using IntRandom =
    dist_and_gen&lt;std::uniform_int_distribution&lt;T&gt;&gt;;
template&lt;class T&gt; using FloatRandom =
    dist_and_gen&lt;std::uniform_float_distribution&lt;T&gt;&gt;;
template&lt;class T&gt; using BoolRandom =
    dist_and_gen&lt;std::bernoulli_distribution&lt;T&gt;&gt;;


This version loses some of the details, such as your custom-named accessors for the parameters; but it preserves a lot of the details "accidentally". For example, I didn't try to preserve your BoolRandom::BoolRandom() default constructor; but it turns out that it just works anyway, thanks to the default constructor of the standard bernoulli_distribution.