专门针对bool+积分+浮点返回类型的模板
specializing a template on bool + integral + floating-point return types
我想写一个函数模板,它返回各种类型的随机变量(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:"匿名命名空间"::randomPrimitive":对重载函数的调用不明确
当我尝试编译时:
randomPrimitive<float>();
有没有一种方法可以专门化函数模板,这样我就可以为bool、其他积分类型和浮点类型编写三种不同的实现?
您的编辑工作已接近尾声。您需要将您的"积分"版本限制为积分类型。这将消除歧义:
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
如果这仍然没有输出你想要的,希望你有足够的方向来实现它。
模板专用化的语法不正确。试试这个:
template<>
bool randomPrimitive<bool>()
{
std::uniform_int_distribution<signed char> dst;
std::mt19937 rng;
return dst(rng) >= 0;
}
不同之处在于函数名称randomPrimitive
和参数列表()
之间的<bool>
。
类型char
可以是unsigned char
或signed char
——这取决于编译器。您的实现显然取决于char
被解释为signed char
,所以您应该明确这一点。
此外,其中x
是bool
表达式的表达式x ? true : false
与简单的x
相同。
您不进行专门化(完全专门化除外),而是重载函数模板。重载只对参数类型有效,对结果类型无效。由于您的函数模板不接受任何参数,因此过载解析无法决定为您选择什么。
在这种情况下,您必须指定模板参数,或者尝试使用转换运算符:
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;
- 如何获取std::result_of函数的返回类型
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 函数作为模板参数,是否对返回类型强制约束
- C++中函数的向量返回类型引发错误
- 检查函数返回类型是否与STL容器类型值相同
- 为什么返回类型中需要typename?C++
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 推导 std::vector::back() 的返回类型
- 在 c++ 中将函数返回类型指定为模板参数
- 专门针对bool+积分+浮点返回类型的模板
- diab 5.7编译器中的逻辑与运算符返回非bool类型
- 当函数返回类型为 bool 时,为什么我不能在 C++14 中返回共享指针?
- 为什么返回Windows BOOL数据类型而不返回int