c++ - C ++模板函数 - 多种类型,默认和...参数?
问题描述
我有几个样板函数,我想用模板替换。它们看起来大致如下:
std::vector<double> generate_means(
std::mt19937& g, unsigned int N,
double lower = -1.0, double upper = 1.0
) {
std::uniform_real_distribution<double> dist(lower, upper);
std::function<double()> rng = std::bind(dist, g);
std::vector<double> res(N);
std::generate(std::begin(res), std::end(res), gen);
return res;
}
需要抽象的元素是返回类型(仅包含类型,总是vector
可以的)后面的参数N
(例如,lower
在upper
这种情况下)和分布(例如,std::uniform_real_distribution
)。
我想大致能够写什么:
auto generate_means = generate_template<
double, // results vector<double>
std::uniform_real_distribution, // uses uniform distro
double=-1.0,double=1.0 // with default args
>
auto generate_norm_deviates = generate_template<
double, // still provides vector<double>
std::normal_distribution, // different distro
double=0, double=1.0 // different defaults
>
auto generate_category_ids = generate_template<
unsigned int,
std::uniform_int_distribution,
unsigned int=0, unsigned int // again with two args, but only one default
>
我有一些子片段
template <class NUMERIC>
using generator = std::function<NUMERIC()>;
template <class NUMERIC>
std::vector<NUMERIC> series(unsigned int length, generator<NUMERIC> gen) {
std::vector<NUMERIC> res(length);
std::generate(std::begin(res), std::end(res), gen);
return res;
};
但是当我尝试组装时,例如
template <class NUMERIC, class DIST, class...Args>
std::vector<NUMERIC> generator_template(
std::mt19937& g, unsigned int N,
Args... args
) {
DIST<NUMERIC> dist(&args...);
generator<NUMERIC> gen = std::bind(dist, g);
return series(N, gen);
}
我遇到编译错误(在这种情况下error: expected unqualified-id
)。我想要的大约可以实现吗?这种方法是否朝着正确的方向发展,还是我需要做一些根本不同的事情?如果方向正确,我错过了什么?
编辑:
对于应用程序约束:我希望能够声明具有参数默认值的生成器,但我确实需要偶尔在没有默认值的情况下使用它们。没有默认值只是不方便,但不是致命的。例子:
//... assorted calculations...
auto xmeans = generate_means(rng, 100); // x on (-1,1);
auto ymeans = generate_means(rng, 100); // y on (-1,1);
auto zmeans = generate_means(rng, 100, 0, 1); // z on (0,1);
解决方案
不可能有浮点数作为模板参数。但是,您可以执行以下操作:
#include <random>
#include <limits>
#include <algorithm>
#include <vector>
#include <iostream>
template<typename T, template<typename> typename Distribution>
auto generate_random_template(T min = std::numeric_limits<T>::lowest(),
T max = std::numeric_limits<T>::max()) {
return [distribution = Distribution<double>{min, max}]
(auto &&generator, std::size_t number) mutable {
std::vector<T> result;
result.reserve(number);
auto generate = [&](){return distribution(generator);};
std::generate_n(std::back_inserter(result), number, generate);
return result;
};
}
int main() {
auto generate_means = generate_random_template<double, std::uniform_real_distribution>(0.0, 1.0);
std::mt19937 g;
std::vector<double> randoms = generate_means(g, 10);
for(auto r : randoms) std::cout << r << std::endl;
return 0;
}
编辑:出于性能原因使用generate_n
而不是generate
EDIT2:如果你想像 x、y 和 z 一样使用默认参数,你也可以这样做:
#include <random>
#include <limits>
#include <algorithm>
#include <vector>
#include <iostream>
template<typename T, template<typename> typename Distribution>
auto generate_random_template(T min = std::numeric_limits<T>::lowest(),
T max = std::numeric_limits<T>::max()) {
return [distribution = Distribution<double>{min, max}, min, max]
(auto &&generator, std::size_t number, auto ...args) mutable {
std::vector<T> result;
result.reserve(number);
if constexpr(sizeof...(args) > 0)
distribution.param(typename Distribution<T>::param_type(args...));
else
distribution.param(typename Distribution<T>::param_type(min, max));
auto generate = [&](){return distribution(generator);};
std::generate_n(std::back_inserter(result), number, generate);
return result;
};
}
int main() {
auto generate_means = generate_random_template<double, std::uniform_real_distribution>(-1.0, 1.0);
std::mt19937 g;
// x and y are between -1 and 1
std::vector<double> x = generate_means(g, 10);
std::vector<double> y = generate_means(g, 10);
std::vector<double> z = generate_means(g, 10, 0.0, 1.0); // z is between 0 and 1
for(int i = 0; i < 10; ++i) {
std::cout << x[i] << "," << y[i] << "," << z[i] << std::endl;
}
return 0;
}
推荐阅读
- javascript - 我可以将 HTML 属性传递给 *ngIf 中的函数吗?
- excel - VBA "Variable required. Can't assign to this expression" error - Goal-seek analysis
- javascript - 通过纯 Javascript 使用类、标题、段落、编号和删除按钮在单击时创建 div
- database - 通过 hyper 使用 mongoDB 的设置不起作用
- flutter - 横幅 Google 广告未显示 - 广告加载失败:LoadAdError(代码:3,域:com.google.android.gms.ads,消息:无广告配置。)
- c# - 在 Entity Framework 6 下工作的查询在 .Net5 中不起作用
- java - 使用 BroadcastReceiver 传递数据时出错
- vue.js - 单独的登录组件而不是处理组件 vuejs
- python - 如何通过python删除最后一个\n\n\n\n之后的行
- reactjs - Primereact 树:选择一个节点将在 React Player 中显示视频