C++模板函数-多种类型,默认和..争论
C++ template function - multiple types, default and ... arguments?
我有几个锅炉板函数想用模板替换。它们看起来大致像:
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
编辑2:如果你想像对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;
}
感谢各种各样的评论者,这现在正在工作(当从Q添加到工作块时):
template <class NUMERIC, template<class> class DIST, class ... Args>
std::vector<NUMERIC> generator_template(
std::mt19937& g, unsigned int N,
Args &&... args
) {
DIST<NUMERIC> dist(std::forward<Args>(args)...);
generator<NUMERIC> gen = std::bind(dist, g);
return series(N, gen);
};
auto generate_test = generator_template<double, std::uniform_real_distribution, double, double>;
不过,很高兴看到其他答案——仍在努力理解C++模板语法,并且更喜欢让我设置默认参数的版本。
我很想接受一个构造的分布对象。
template <typename Dist, typename URBG>
std::vector<typename Dist::value_type> generate(Dist&& dist, URBG&& gen, std::size_t N)
{
std::vector<typename Dist::value_type> res(N);
std::generate(res.begin(), res.end(), std::bind(std::forward<Dist>(dist), std::forward<URBG>(gen)));
return res;
}
相关文章:
- 具有默认模板类型的默认构造函数的类型推导
- C++(和 ROS) - 包含与前向声明引用,设置默认值和类型定义
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 创建类类型的动态分配数组,其中类不得具有默认构造函数
- 模板类默认类型和条件
- Visual Studio 2019 - 设置文件类型的默认扩展名
- 对于具有引用返回类型的搜索算法,默认返回值应该是什么?
- 如果输入类型与目标类型不同,"cin"变量是否重置为某个默认值?
- 为什么 std::optional::value_or 没有默认 ctor 类型的专用化?
- 静态私有函数,模板化类型作为C++中的默认参数
- 当为模板参数提供默认参数时,VS 2017无法正确找到以前定义的类型
- 具有默认类型和值的模板参数
- 如果我想从类型"T"定义元素的容器(来自 STL),那么"T"必须使用默认构造函数?
- 如果类在 C++ 中具有常量或引用类型的非静态数据成员,为什么编译器不提供默认赋值运算符?
- 在一行中将默认类型值上的指针作为参数传递
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 使用返回不完整类型的函数作为默认参数
- 更改代码::块上的默认保存文件类型
- 构造函数可以更改默认成员类型吗?
- 检测习惯用语和默认参数类型匹配