An overloaded random number function template using modern C++ I don't mess around a lot with templates (or with GTK), but today I wrote something and would like to know how it can be improved, and hopefully clarify a few things in the process.

So, Randolfi() is a function template which returns a random number. A range can be specified as arguments.

It uses features new to C++11, based on these:


How to generate a random number in C++?
Random number generation in C++11 , how to generate , how do they work?


(The name "Randolfi" is a joke made by a few colleagues regarding my last name, Ranolfi.)

randolfi.hpp

#ifndef RANDOLFI_HPP
#define RANDOLFI_HPP

#include &lt;random&gt;

template &lt;typename T&gt;
T Randolfi()
{
    std::mt19937 rng;
    rng.seed( std::random_device()() );
    std::uniform_int_distribution&lt;T&gt; dist;
    return dist(rng);
}

template &lt;typename T&gt;
T Randolfi(T range_start, T range_end)
{
    std::mt19937 rng;
    rng.seed( std::random_device()() );
    std::uniform_int_distribution&lt;T&gt; dist(range_start, range_end);
    return dist(rng);
}

#endif //RANDOLFI_HPP


randolfi-test.cpp

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;gtkmm.h&gt;
#include "randolfi.hpp"

using namespace std;

int main()
{
    auto app = Gtk::Application::create();

    uint a_random_number = Randolfi&lt;uint&gt;();

    Gtk::MessageDialog dialog( to_string(a_random_number) );    
    dialog.run();


    return 0;
}




Notes:


Somehow it doesn't feel right to have such a large proportion of redundant lines across the function overloads. I think there might be a template-related trick to help here, but searching for it proved useless since all the results I found (like this one) are concerned about type parameter overloading, which is not my case.
I though about declaring it as Randolfi(T range_start = NULL, T range_end = NULL) and then checking if (range_start != NULL &amp;&amp; range_end != NULL), but that does not save me any lines, and also appears to be frowned upon.
As it is, the function can be called without type argument for the second overload, but not for the first one:

Randolfi(0, 100);  // type parameter ommited for template
Randolfi();  // Fails - compiler has no clue on know how to instantiate template


I have a feeling this inconsistency is bad practice.
I'm mostly concerned about the template header, but I did include my testing code (randolfi-test.cpp) to this question so maybe someone can let me know if I did something terribly wrong. From my part, I'd like to avoid calling Gtk::Application::create() but that doesn't seem to be possible.


Thanks!
The constructor of uniform_int_distribution has default arguments:
template&lt;typename T&gt;
explicit uniform_int_distribution(T a = 0, 
                                  T b = std::numeric_limits&lt;T&gt;::max());

(I don't know why a defaults to 0 rather than to the minimum T, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template &lt;typename T&gt;
T Randolfi(T range_start = 0,
           T range_end = std::numeric_limits&lt;T&gt;::max())
{
    std::uniform_int_distribution&lt;T&gt; dist(range_start, range_end);
    return dist(rng);
}

Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template &lt;typename T, typename... Args&gt;
T Randolfi(Args&amp;&amp;... args)
{
    std::uniform_int_distribution&lt;T&gt; dist(std::forward&lt;Args&gt;(args)...);
    return dist(rng);
}

We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.

Don't recreate a random generator every call.  You could make it static, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T, and test with implicit and explicit range.  Also, avoid using namespace std;, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).

Modified code
#include &lt;limits&gt;
#include &lt;random&gt;
#include &lt;utility&gt;

static auto rng = []{
    std::mt19937 rng;
    rng.seed(std::random_device()());
    return rng;
}();

template &lt;typename T,
          template&lt;typename&gt; typename Distribution
                                      = std::uniform_int_distribution,
          typename... Args&gt;
T Randolfi(Args&amp;&amp;... args)
{
    Distribution&lt;T&gt; dist(std::forward&lt;Args&gt;(args)...);
    return dist(rng);
}

#include &lt;iostream&gt;

int main()
{
    std::clog &lt;&lt; Randolfi&lt;int&gt;(-100, +100) &lt;&lt; '\n'
              &lt;&lt; Randolfi&lt;char&gt;('a', 'z') &lt;&lt; '\n'
              &lt;&lt; Randolfi&lt;double, std::normal_distribution&gt;(100, 15) &lt;&lt; '\n'
              &lt;&lt; Randolfi&lt;std::size_t&gt;() &lt;&lt; std::endl;
}