使用可变模板的随机选取器函数——这是可能的吗
random picker function using variadic templates -- is it possible?
我想使用C++11的可变模板来实现一个通用的"随机选择器"函数。
像这样的。。。
template <typename T>
T randomPicker(T one, T two, T three)
{
int pick = 3 * (rand() / double(RAND_MAX));
switch (pick)
{
case 0:
return one;
case 1:
return two;
default:
return three;
}
}
除非被泛化为接受任何数量的参数(如上所述,每个参数都是相同的类型——尽管接受任何类型作为参数并在返回时将所选类型转换为某个特定类型T也是可以接受的(。
我理解使用模板递归来实现typesafe printf等功能的想法。可变模板也可以用于创建上述类型的函数吗?任何提示都将不胜感激!
类似的东西,尽管我不能测试它:
template <typename First, typename... Others>
First randompicker(First first, Others ...args) {
const size_t len = sizeof...(args) + 1;
if (rand() / double(RAND_MAX) < 1.0 / len) {
return first;
}
return randompicker(args...);
}
template <typename Only>
Only randompicker(Only only) {
return only;
}
我不确定那里的重载是否正确——大概一个参数包可以是空的,我不知道我是否仍然可以为一个参数重载而不产生歧义。
诚然,这比您的3个参数的示例使用了更多的随机数,并且可能对舍入误差的偏差更敏感。因此,您可以在开始时从0
到len-1
中选择一个随机数,然后调用一个递归函数,从参数包中选择第n
个参数:
template <typename First, typename... Others>
First select(size_t idx, First first, Others ...args) {
if (idx == 0) return first;
return select(idx-1, args...);
}
template <typename Only>
Only select(size_t, Only only) {
return only;
}
template <typename First, typename... Others>
First randompicker(First first, Others ...args) {
static std::default_random_engine re;
const size_t len = sizeof...(args) + 1;
std::uniform_int_distribution<size_t> range{0, len - 1};
const size_t idx = range(re);
return select(idx, first, args...);
}
在所有情况下,我都有n
if/else语句,而不是n
路开关。您可能很幸运有了优化器,或者您可以通过First
、Second
。。。变量args之前的A few
参数args。
我不确定是否必须使用可变模板,但IMHO使用初始值设定项列表更容易。
#include <cstddef>
#include <iostream>
#include <random>
#include <algorithm>
#include <initializer_list>
using namespace std;
template <class T>
T random_picker(initializer_list<T> container){
static default_random_engine re;
uniform_int_distribution<size_t> range{0, container.size()-1};
auto random_iterator = container.begin();
advance(random_iterator, range(re));
return *random_iterator;
}
int main(){
for(size_t i = 0; i < 10; ++i)
cout << random_picker({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) << endl;
}
一种方法是你可以做这样的事情:
template<typename T, typename... Args>
T randomPicker(T first, Args ...rest) {
T array[sizeof...(rest) + 1] = {first, rest...};
return array[rand() % (sizeof...(rest) + 1)];
}
在IdeOne 上测试
这应该可以工作。randomPicker
选择它将返回哪一个参数。randomPicker_impl
通过参数进行工作,直到选择正确的参数。Last
的重载确保模板扩展终止。
完整的工作代码:ideone.com/2TEH1
template< typename Ret, typename Last >
Ret random_picker_impl( size_t i, Last&& last )
{
return std::forward<Last>(last);
}
template< typename Ret, typename First, typename Second, typename ... Rest >
Ret random_picker_impl( size_t i, First&& first, Second&& second, Rest&&... rest )
{
if( i == 0 )
{
return std::forward<First>(first);
}
else
{
return random_picker_impl<Ret>( i-1, std::forward<Second>(second), std::forward<Rest>(rest)... );
}
}
template< typename First, typename ... Rest >
First random_picker( First&& first, Rest&&... rest )
{
size_t index = (sizeof...(rest) + 1) * (std::rand() / double(RAND_MAX));
return random_picker_impl<First>( index, std::forward<First>(first), std::forward<Rest>(rest)... );
}
选择链表中随机元素的常用方法是给出1/1,1/2,1/3。。。,1/n在每个链路上用当前元素替换所拾取的元素的机会。
#include <cstdlib>
#include <ctime>
#include <iostream>
namespace {
template<typename T>
T randomPickerHelper(int& sz, T first) {
return first;
}
template<typename T, typename ...Args>
T randomPickerHelper(int& sz, T first, Args ...rest) {
T next = randomPickerHelper(sz, rest...);
return std::rand() % ++sz ? next : first;
}
}
template<typename T, typename... Args>
T randomPicker(T first, Args ...rest) {
int sz = 1;
return randomPickerHelper(sz, first, rest...);
}
int main() {
std::srand(std::time(0));
for (int i = 0; i < 1000000; ++i) {
std::cout << randomPicker(1, 2, 3, 4, 5) << std::endl;
}
return 0;
}
不过,多次调用rand()
。
template<typename T, typename ...Args>
struct Count {
static const int sz = Count<Args...>::sz + 1;
};
template<typename T>
struct Count<T> {
static const int sz = 1;
};
template<typename T>
T pick(int n, T first) {
return first;
}
template<int N, typename T, typename ...Args>
T pick(int n, T first, Args ...rest) {
if (n == Count<T, Args...>::sz) {
return first;
}
return pick(n, rest...);
}
template<typename T, typename ...Args>
T randomPicker(T first, Args ...rest) {
return pick(std::rand() % Count<T, Args...>::sz + 1, first, rest...);
}
我觉得这应该是可能的,但GCC 4.6.0不支持扩展<Args...>
。
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 循环中的随机函数
- 在c++构造函数中使用随机字符串生成器
- 将字符随机转换为大写的函数
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 使用指针在分区函数中实现随机分区点
- 如何使用可选的随机种子参数创建 roll_die() 函数
- 如何调用随机函数
- 如何在 C++ 中获取随机函数的周期性
- C++ Arduino - 随机函数不起作用
- RCPP 函数,用于在 4 个方向上生成随机游走
- 动态数组传递给 main 中用随机值填充的函数,返回值3221226356
- 通过函数传递随机引擎-为什么不同的编译器表现不同
- 朋友函数随机行为
- 为什么我的函数名称中会随机出现一个额外的字母
- 如何编写一个递归函数,以随机的方式混淆从0到6的数字
- 我在运行函数 GetVolumeInformation() 时得到非常随机的结果
- 从 C# 模块调用C++函数引发随机崩溃
- 除法函数随机整数需要打印出商和余数
- c++分裂函数随机崩溃