使用枚举指定的函数填充矢量
Fill vector using function specified by enum
我想要的功能如下:
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;
}
我觉得这并不令人满意,因为有很多代码重复。环顾四周,我发现了STL算法std::generate()
,它可以使用函子填充向量,函子可以有一个增量成员来扮演i
的角色。
我看到了两条潜在的路线。第一种是使用工厂来初始化函子。这种方法的问题是代码分离(如上所述,不同的情况很好地保持在一起),并且需要多个新类来增加开销。
第二个是使用lambda函数(我对它的经验很少)。这很好,因为我可以在switch语句中的一行中定义每个函数。但我不知道如何避免作用域问题(lambda函数在switch语句的作用域之外是不可访问的)。
有没有使用lambda函数的解决方案?从效率和可读性的角度来看,什么是最好的选择?
也许你想要这样的东西。。。?(点击此处查看
#include <iostream>
#include <vector>
#include <cmath>
#include <functional>
enum Func { Sin, Sinc };
std::vector<float> f(int n, Func func)
{
std::vector<float> results(n);
float tmp = (n - 1) / 2.0;
int i;
std::function<float()> fns[] = {
[&] { return sin(M_PI * i / tmp); },
[&] { return sin(M_PI * i / tmp) / (M_PI * i / tmp); }
};
auto& fn = fns[func];
for (i=0; i<n; ++i)
results[i] = fn();
return results;
}
int main()
{
std::vector<float> x = f(10, Sin);
for (auto& v : x) std::cout << v << ' '; std::cout << 'n';
std::vector<float> y = f(10, Sinc);
for (auto& v : y) std::cout << v << ' '; std::cout << 'n';
}
输出:
0 0.642788 0.984808 0.866025 0.34202 -0.34202 -0.866025 -0.984808 -0.642788 -2.44929e-16
-nan 0.920725 0.705317 0.413497 0.122477 -0.0979816 -0.206748 -0.201519 -0.115091 -3.89817e-17
一个可能不快(每个函数调用都有间接寻址)但更灵活的选项是创建std::map<FuncType, std::function<float(int,float)>>
。你不能使用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;
}
}
现在我们有了这个,我们需要填充一个函子映射:
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();
(如果你喜欢,你可以使用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;
}
添加新函数只需要在create_functype_map()
中填充映射。请注意,generate_i()
循环中的每个迭代都将调用std::function
上的operator()
,这将需要一定程度的间接性来解析调用,类似于虚拟方法调用的开销。这将在性能方面花费一些成本,但对您来说可能不是问题。
(参见演示)
您可以编写一个通用类,用于标准算法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;
}
输出为
0 5 10 15 20 25 30 35 40 45
5 10 15 20 25 30 35 40 45 50
当然,您可以使用自己的lambda表达式,其中包括一些数学函数,如sin
- 如何将零填充的多维数组传递给 C++ 中的函数?
- 填充上编译器生成的复制构造函数之间的不一致
- 如何使用(lambda)函数填充C++容器
- 从函数填充的字符串的推导向量到 int 的字符串
- parallel_for lambda 函数填充 2D 向量后出错
- 在使用结构体和用函数填充其变量(使用指针)时遇到问题
- 尝试使用函数填充2维数组
- 如何使用静态函数填充静态 std::map
- 使用 C 函数填充 QByteArray
- 尝试用函数填充线程向量 - 错误
- 如何使用FormatMessage函数填充系统错误消息的va_list
- 使用枚举指定的函数填充矢量
- 为什么我不能用这个其他类的函数填充这个类的函数指针
- 函数填充向量,但它在某个时刻变为空
- 使用函数填充数组中的数字.如果数组已满,则该数字将在第二个数组中填充
- 用函数c++填充指针数组
- 使用派生类构造函数填充基类受保护成员
- 用构造函数填充向量的C++奇怪行为
- 使用/不使用c++内部函数填充
- 返回Boost分布生成器从函数填充向量在c++中