C++ 使用枚举指定的函数填充向量
我想要的功能如下:C++ 使用枚举指定的函数填充向量,c++,enums,lambda,factory,C++,Enums,Lambda,Factory,我想要的功能如下: std::vector<float> GetFuncVec(int N, FuncType type) { std::vector<float> fn(N); float tmp = (N - 1) / 2.0; switch (type) { case SIN: for (int i=0; i<N; ++i) fn[i] = sin(M_PI * i / tmp);
std::vector<float> GetFuncVec(int N, FuncType type)
{
std::vector<float> fn(N);
float tmp = (N - 1) / 2.0;
switch (type) {
case SIN:
for (int i=0; i<N; ++i)
fn[i] = sin(M_PI * i / tmp);
break;
case SINC:
for (int i=0; i<N; ++i)
fn[i] = sin(M_PI * i / tmp) / (M_PI * i / tmp);
break;
...
}
return fn;
}
std::vector GetFuncVec(int N,FuncType类型)
{
std::载体fn(N);
浮动tmp=(N-1)/2.0;
开关(类型){
案例SIN:
对于(int i=0;i也许您想要这样的东西…?(看到了吗
也许你想要这样的东西…?(看到了吗
一个可能不快(每个函数调用都有间接寻址)但更灵活的选项是创建一个std::map
。您不能使用std::generate()
,因为您需要参数i
来计算结果,但编写自己的结果并不难:
template <typename Iterator, typename Generator, typename Index, typename... Args>
void generate_i(Iterator first, Iterator last, Generator gen, Index i, Args... args)
{
while (first != last) {
*first = gen(i, args...);
++i;
++first;
}
}
模板
void generate_ui(迭代器优先,迭代器last,Generator,Index i,Args…Args)
{
while(第一个!=最后一个){
*第一个=发电机(i,args…);
++一,;
++第一,;
}
}
现在我们有了这个,我们需要填充一个函子映射:
using FuncTypeFunction = std::function<float(int,float)>;
using FuncTypeFunctionMap = std::map<FuncType, FuncTypeFunction>;
FuncTypeFunctionMap create_functype_map()
{
FuncTypeFunctionMap functions;
functions[SIN] = [] (int i, float tmp) {
return sin(M_PI * i / tmp);
};
functions[SINC] = [] (int i, float tmp) {
return sin(M_PI * i / tmp) / (M_PI * i / tmp);
};
// ...
return functions;
}
FuncTypeFunctionMap const FuncTypeFunctions = create_functype_map();
使用FuncTypeFunction=std::function;
使用FuncTypeFunctionMap=std::map;
FuncTypeFunctionMap创建函数类型映射()
{
FuncTypeFunctionMap函数;
函数[SIN]=[](int i,float tmp){
返回sin(M_PI*i/tmp);
};
函数[SINC]=[](int i,浮点tmp){
返回sin(mu-PI*i/tmp)/(mu-PI*i/tmp);
};
// ...
返回函数;
}
FuncTypeFunctionMap常量FuncTypeFunctions=创建函数类型映射();
(如果愿意,可以使用boost.assign提高该位的可读性。)
最后,我们可以使用这张地图:
std::vector<float> GetFuncVec(int N, FuncType type)
{
std::vector<float> fn(N);
float tmp = (N - 1) / 2.0;
auto func = FuncTypeFunctions.find(type);
if (func != FuncTypeFunctions.end()) {
generate_i(fn.begin(), fn.end(), func->second, 0, tmp);
}
return fn;
}
std::vector GetFuncVec(int N,FuncType类型)
{
std::载体fn(N);
浮动tmp=(N-1)/2.0;
auto func=FuncTypeFunctions.find(type);
if(func!=FuncTypeFunctions.end()){
生成_i(fn.begin(),fn.end(),func->second,0,tmp);
}
返回fn;
}
添加新函数只需要在create\u functype\u map()
中填充映射。请注意,generate\u i()
循环中的每次迭代都将调用操作符()std::function
上的
,这将需要一定程度的间接寻址来解析调用,类似于虚拟方法调用的开销。这将在性能方面花费一些成本,但对您来说可能不是问题
()一个可能不快(每个函数调用都有间接寻址)但更灵活的选项是创建一个std::map
。您不能使用std::generate()
,因为您需要参数i
来计算结果,但编写自己的结果并不难:
template <typename Iterator, typename Generator, typename Index, typename... Args>
void generate_i(Iterator first, Iterator last, Generator gen, Index i, Args... args)
{
while (first != last) {
*first = gen(i, args...);
++i;
++first;
}
}
模板
void generate_i(迭代器优先、迭代器最后、生成器生成、索引i、Args…Args)
{
while(第一个!=最后一个){
*第一个=发电机(i,args…);
++一,;
++第一,;
}
}
现在我们有了这个,我们需要填充一个函子映射:
using FuncTypeFunction = std::function<float(int,float)>;
using FuncTypeFunctionMap = std::map<FuncType, FuncTypeFunction>;
FuncTypeFunctionMap create_functype_map()
{
FuncTypeFunctionMap functions;
functions[SIN] = [] (int i, float tmp) {
return sin(M_PI * i / tmp);
};
functions[SINC] = [] (int i, float tmp) {
return sin(M_PI * i / tmp) / (M_PI * i / tmp);
};
// ...
return functions;
}
FuncTypeFunctionMap const FuncTypeFunctions = create_functype_map();
使用FuncTypeFunction=std::function;
使用FuncTypeFunctionMap=std::map;
FuncTypeFunctionMap创建函数类型映射()
{
FuncTypeFunctionMap函数;
函数[SIN]=[](int i,float tmp){
返回sin(M_PI*i/tmp);
};
函数[SINC]=[](int i,浮点tmp){
返回sin(mu-PI*i/tmp)/(mu-PI*i/tmp);
};
// ...
返回函数;
}
FuncTypeFunctionMap常量FuncTypeFunctions=创建函数类型映射();
(如果愿意,可以使用boost.assign提高该位的可读性。)
最后,我们可以使用这张地图:
std::vector<float> GetFuncVec(int N, FuncType type)
{
std::vector<float> fn(N);
float tmp = (N - 1) / 2.0;
auto func = FuncTypeFunctions.find(type);
if (func != FuncTypeFunctions.end()) {
generate_i(fn.begin(), fn.end(), func->second, 0, tmp);
}
return fn;
}
std::vector GetFuncVec(int N,FuncType类型)
{
std::载体fn(N);
浮动tmp=(N-1)/2.0;
auto func=FuncTypeFunctions.find(type);
if(func!=FuncTypeFunctions.end()){
生成_i(fn.begin(),fn.end(),func->second,0,tmp);
}
返回fn;
}
添加新函数只需要在create\u functype\u map()
中填充映射。请注意,generate\u i()
循环中的每次迭代都将调用操作符()std::function
上的
,这将需要一定程度的间接寻址来解析调用,类似于虚拟方法调用的开销。这将在性能方面花费一些成本,但对您来说可能不是问题
()您可以编写一个通用类,用于标准算法std::iota
比如说
#include <iostream>
#include <functional>
#include <vector>
#include <numeric>
class Value
{
public:
Value() : i( 0 ), fn( []( size_t i ) { return ( float )i; } ) {}
Value & operator ++() { ++i; return *this; }
operator float () const { return fn( i ); }
Value & operator =( std::function<float( size_t )> fn )
{
this->fn = fn;
return *this;
}
private:
size_t i;
std::function<float( size_t )> fn;
};
enum E { First, Second };
std::vector<float> f( size_t N, E e )
{
Value value;
float tmp = N / 2.0f;
switch( e )
{
case First:
value = [tmp] ( size_t i ) { return i * tmp; };
break;
case Second:
value = [tmp] ( size_t i ) { return i * tmp + tmp; };
break;
}
std::vector<float> v( N );
std::iota( v.begin(), v.end(), value );
return v;
}
int main()
{
for ( float x : f( 10, First ) ) std::cout << x << ' ';
std::cout << std::endl;
for ( float x : f( 10, Second ) ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
当然,您可以使用自己的lambda表达式,其中包括一些数学函数,如sin
您可以编写一个通用类,用于标准算法std::iota
比如说
#include <iostream>
#include <functional>
#include <vector>
#include <numeric>
class Value
{
public:
Value() : i( 0 ), fn( []( size_t i ) { return ( float )i; } ) {}
Value & operator ++() { ++i; return *this; }
operator float () const { return fn( i ); }
Value & operator =( std::function<float( size_t )> fn )
{
this->fn = fn;
return *this;
}
private:
size_t i;
std::function<float( size_t )> fn;
};
enum E { First, Second };
std::vector<float> f( size_t N, E e )
{
Value value;
float tmp = N / 2.0f;
switch( e )
{
case First:
value = [tmp] ( size_t i ) { return i * tmp; };
break;
case Second:
value = [tmp] ( size_t i ) { return i * tmp + tmp; };
break;
}
std::vector<float> v( N );
std::iota( v.begin(), v.end(), value );
return v;
}
int main()
{
for ( float x : f( 10, First ) ) std::cout << x << ' ';
std::cout << std::endl;
for ( float x : f( 10, Second ) ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
当然,您可以使用自己的lambda表达式,其中包括一些数学函数,如sin
“lambda函数在switch语句的范围外不可访问”--为什么不可以?“lambda函数在switch语句的范围外不可访问”--为什么不呢?它的优点是包含在单个函数中f()
。但是,我更喜欢在定义每个函数时使用枚举,以防顺序发生变化。这应该是包括Func::NFuncs
enum的问题,对吗?是-NFuncs
是一种合理的编译时方法,可以调整fns[]
,然后你必须确保你没有忘记插入一个元素。顺便说一句-如果你的调用代码总是硬编码其中一个函数,你可以使用模板f()
,而根本不需要数组,然后调用alaauto x=f(10)
…很可能更快更可靠,但我想你知道这一点,而且这不是你的使用scanerio…对。我想保留在运行时配置函数的功能。谢谢。@DavidHall只是在想…你可以有std::pair={Sin,[&]{Sinc,[&]},{Sinc,[&]}};
-然后对fns
进行迭代,可以检查索引是否在增加…证明顺序没有改变(虽然可能是运行时)-co