specializing a template on bool + integral + floating-point return types

c++, c++11

Solution

You're getting close with your edits. You need to restrict your "integral" version to integral types. That will get rid of the ambiguity:

template<typename T>
typename std::enable_if
<
    std::is_integral<T>::value,
    T
>::type
randomPrimitive()

But if you run it now with something like this:

#include <iostream>

int
main()
{
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<float>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<double>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << (int)randomPrimitive<signed char>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<unsigned>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<bool>() << '\n';
}

You'll get something like:

0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
92
92
92
92
92
92
92
92
92
92
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
1
1
1
1
1
1
1
1
1
1

Getting there, but not exactly random. The problem is that you are constructing a new engine every time you use it. What you want is to create a URNG once, and then keep getting random bits out of it:

std::mt19937&
get_eng()
{
    static std::mt19937 eng;
    return eng;
}

And you should really only create your distributions once too. Most of them are stateless, but not all of them. Best just to assume all of them carry state, and you don't want to throw that state away.

static std::uniform_real_distribution<T> dst;

This will greatly improve things, but you're not there yet:

0.814724
0.135477
0.905792
0.835009
0.126987
0.968868
0.913376
0.221034
0.632359
0.308167
0.547221
0.188382
0.992881
0.996461
0.967695
0.725839
0.98111
0.109862
0.798106
0.297029
92
13
49
122
46
7
105
45
43
8
2816384844
3427077306
153380495
1551745920
3646982597
910208076
4011470445
2926416934
2915145307
1712568902
0
1
1
1
1
0
1
0
1
0

I note that all 10 of the values from `signed char` are positive. That doesn't look right. It turns out that `std::uniform_int_distribution` has a constructor that looks like this:

explicit uniform_int_distribution(IntType a = 0,
                                  IntType b = numeric_limits<IntType>::max());

I'm guessing that's not what you want, so:

static std::uniform_int_distribution<T> dst(std::numeric_limits<T>::min(), 
                                            std::numeric_limits<T>::max());

And finally, if you want a random `bool`, go with the `std::bernoulli_distribution`.

Putting this all together:

#include <random>

std::mt19937&
get_eng()
{
    static std::mt19937 eng;
    return eng;
}

template<typename T>
typename std::enable_if
<
    std::is_integral<T>::value,
    T
>::type
randomPrimitive()
{
    static std::uniform_int_distribution<T> dst(std::numeric_limits<T>::min(), 
                                                std::numeric_limits<T>::max());
    return dst(get_eng());
}

template<>
bool
randomPrimitive<bool>()
{
    static std::bernoulli_distribution dst;
    return dst(get_eng());
}

template<typename T>
typename std::enable_if
<
    std::is_floating_point<T>::value,
    T
>::type
randomPrimitive()
{
    static std::uniform_real_distribution<T> dst;
    return dst(get_eng());
}

#include <iostream>

int
main()
{
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<float>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<double>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << (int)randomPrimitive<signed char>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<unsigned>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<bool>() << '\n';
}

Which for me outputs:

0.814724
0.135477
0.905792
0.835009
0.126987
0.968868
0.913376
0.221034
0.632359
0.308167
0.547221
0.188382
0.992881
0.996461
0.967695
0.725839
0.98111
0.109862
0.798106
0.297029
92
13
-79
-6
46
-121
-23
45
43
8
2816384844
3427077306
153380495
1551745920
3646982597
910208076
4011470445
2926416934
2915145307
1712568902
0
1
1
1
1
0
1
0
1
0

And if this still isn't outputting what you intended, hopefully you've got enough direction to take it from here.

Problem

I'd like to write a function template which returns a random variable of various types (bool, char, short, int, float, double, along with unsigned versions of these). I couldn't see how to do this using the latest C++11 standard library, since I need to use either uniform_int_distribution or uniform_real_distribution. I thought I could specialize the template: ``` template<typename T> T randomPrimitive() { std::uniform_int_distribution<T> dst; std::mt19937 rng; return dst(rng); } template<> bool randomPrimitive<bool>() { std::uniform_int_distribution<signed char> dst; std::mt19937 rng; return dst(rng) >= 0 ? true : false; } template<typename T> typename std::enable_if<std::is_floating_point<T>::value, T>::type randomPrimitive() { std::uniform_real_distribution<T> dst; std::mt19937 rng; return dst(rng); } ``` Under Visual Studio 2012 Update 3, this gives: error C2668: '`anonymous-namespace'::randomPrimitive' : ambiguous call to overloaded function when I try to compile: ``` randomPrimitive<float>(); ``` Is there a way to specialize a function template so I can write three different implementations for bool, other integral types, and floating-point types?

Original source