我想写一个函数模板,它返回各种类型的随机变量(bool,char,short,int,float,double,以及这些的无符号版本)。
我无法使用最新的C ++ 11标准库看到如何执行此操作,因为我需要使用uniform_int_distribution或uniform_real_distribution。我以为我可以专门化模板:
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); }
在Visual Studio 2012 Update 3下,这会给出:
错误C2668:'`anonymous-namespace':: randomPrimitive':对重载函数的模糊调用
当我尝试编译时:
randomPrimitive<float>();
有没有办法专门化一个函数模板,所以我可以为bool,其他整数类型和浮点类型编写三种不同的实现?
答案 0 :(得分:12)
您的编辑已经接近了。您需要将“整数”版本限制为整数类型。这将摆脱歧义:
template<typename T>
typename std::enable_if
<
std::is_integral<T>::value,
T
>::type
randomPrimitive()
但如果你现在用这样的东西运行它:
#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';
}
你会得到类似的东西:
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
到达那里,但不是完全随意的。问题是每次使用它时都要构建一个新引擎。你想要的是创建一次URNG,然后不断获取随机位:
std::mt19937&
get_eng()
{
static std::mt19937 eng;
return eng;
}
你应该只创建一次你的发行版。他们中的大多数是无国籍的,但不是全部。最好只是假设所有这些都带有状态,而你不想抛弃那个状态。
static std::uniform_real_distribution<T> dst;
这会大大改善一些事情,但你还没有:
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
我注意到来自signed char
的所有10个值都是正数。这看起来不对。事实证明std::uniform_int_distribution
有一个看起来像这样的构造函数:
explicit uniform_int_distribution(IntType a = 0,
IntType b = numeric_limits<IntType>::max());
我猜这不是你想要的,所以:
static std::uniform_int_distribution<T> dst(std::numeric_limits<T>::min(),
std::numeric_limits<T>::max());
最后,如果您想要随机bool
,请使用std::bernoulli_distribution
。
把这一切放在一起:
#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';
}
对我而言输出:
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
如果这还没有按照你的意图输出,希望你有足够的方向从这里开始。
答案 1 :(得分:1)
您没有专门化(除了完全专业化),您重载函数模板。重载仅适用于参数类型,从不适用于结果类型。由于您的函数模板没有采用任何参数,因此无法通过重载决策来决定要为您挑选的内容。
您必须在这种情况下指定模板参数或尝试使用转换运算符:
struct RandomPrimitive
{
operator float()
{
// your float implementation here
}
operator int()
{
// your int implementation here
}
// more operator type() as needed
};
RandomPrimitive randomPrimitive;
float f = randomPrimitive;
int i = randomPrimitive;
答案 2 :(得分:1)
您的模板特化的语法不正确。试试这个:
template<>
bool randomPrimitive<bool>()
{
std::uniform_int_distribution<signed char> dst;
std::mt19937 rng;
return dst(rng) >= 0;
}
区别在于函数名称<bool>
和参数列表randomPrimitive
之间的()
。
类型char
可以是unsigned char
或signed char
- 这取决于编译器。您的实施明显取决于char
被解释为signed char
,因此您应该明确说明。
此外,x ? true : false
表达式x
表达式bool
与x
表达式完全相同。