接受 std::function 和任意输入作为输入 w/o 模板
Accept std::function with arbitrary inputs as input w/o Templates
出于学习目的:
我正在创建一个小型数值方法库,我正在尝试实现渐变,目前我已经完成了 2D 渐变和 3D 渐变。但我想将其推广到更高的维度。
目前我有:
matrix<double> analysis::gradient_2D(std::function<double(double, double)> fn, double x, double y)
{
matrix<double> R(2, 1);
std::function<double(double)> fnX = [fn, y](double xVar){ return fn(xVar, y); };
std::function<double(double)> fnY = [fn, x](double yVar){ return fn(x, yVar); };
R(1, 1) = differentiateBest(fnX, x);
R(1, 2) = differentiateBest(fnY, y);
return R;
}
matrix<double> analysis::gradient_3D(std::function<double(double, double, double)> fn, double x, double y, double z)
{
matrix<double> R(3, 1);
std::function<double(double)> fnX = [fn, y, z](double xVar){ return fn(xVar, y,z); };
std::function<double(double)> fnY = [fn, x, z](double yVar){ return fn(x ,yVar, z); };
std::function<double(double)> fnZ = [fn, x, y](double zVar){ return fn(x, y, zVar); };
R(1, 1) = differentiateBest(fnX, x);
R(1, 2) = differentiateBest(fnY, y);
R(1, 3) = differentiateBest(fnZ, z);
return R;
}
// Where
double analysis::differentiateBest(std::function<double(double)> fn, double x)
{
return derivative_1_Richardson_6O(fn, x);
}
// For brevity , derivative_1_Richardson_6O also has the same input as differentiateBest
我知道它很冗长,但我喜欢它
问题
我想做的是创建一个
// What do I do at the ... ?
matrix<double> analysis::gradient_ND(std::function<double(...)> fn, matrix<double>)
这样我就可以通过任意输入的 std::function 说 N 我会通过
具有 N 个值的向量。
我将如何着手做这件事?如果答案太长,链接也将不胜感激。
谢谢你。
PS:我看到了一个使用模板的方法,但如果我在实现中使用模板,我将不得不将 .cpp 文件更改为其他文件,对吗?我想避免。如果使用模板是唯一的方法,那么我将不得不妥协。谢谢。
template<class T>
struct array_view {
T* b = nullptr; T* e = nullptr;
T* begin() const { return b; }
T* end() const { return e; }
size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front()const{return *begin(); }
T& back()const{return *std::prev(end()); }
T& operator[](size_t i)const{return begin()[i]; }
array_view( T* s, T* f ):b(s),e(f) {};
array_view() = default;
array_view( T* s, size_t l ):array_view(s, s+l) {}
using non_const_T = std::remove_const_t<T>;
array_view( std::initializer_list<non_const_T> il ):
array_view(il.begin(), il.end()) {}
template<size_t N>
array_view( T(&arr)[N] ):array_view(arr, N){}
template<size_t N>
array_view( std::array<T,N>&arr ):array_view(arr.data(), N){}
template<size_t N>
array_view( std::array<non_const_T,N> const&arr ):
array_view(arr.data(), N){}
template<class A>
array_view( std::vector<T,A>& v):
array_view(v.data(), v.size()){}
template<class A>
array_view( std::vector<non_const_T,A> const& v):
array_view(v.data(), v.size()){}
};
array_view
是对 T
的连续数组的非拥有视图。它具有来自无数连续容器的转换构造函数(如果 matrix
是连续的,则应编写 array_view
的转换器)。
然后:
matrix<double> analysis::gradient_ND(std::function<double(array_view<const double>)>, array_view<const double> pt)
合理。
使用 array_view
不会导致 .h
和 .cpp
代码拆分问题。所涉及的唯一模板要么是固定的(array_view
本身),要么是在构造 array_view
.
时解析的
matrix<double> R(pt.size(), 1);
auto make_tmp = [pt]{
std::vector<double> tmp;
tmp.reserve(pt.size());
for (double x:pt)
tmp.push_back(x);
return tmp;
};
std::vector<std::function<double(double)>> partials;
partials.reserve(pt.size());
for (size_t i = 0; i < pt.size(); ++i) {
partials.push_back(
[&,i](double x){ auto tmp=make_tmp(); tmp[i]=x; return fn(tmp); };
);
}
for (size_t i = 0; i < pt.size(); ++i) {
R(1, i) = differentiateBest(partials[i], pt[i]);
}
return R;
请注意,实际上不需要创建 partials
的数组。你可以直接 differentiateBest
.
partials
重新分配每个呼叫时效率低下。如果您可以让重入不起作用(这通常是可以的),创建一个 tmp
并按值捕获它,并在每次调用 fn
后修改和恢复它,将提高性能。
[&,i,tmp=make_tmp()](double x){ std::swap(tmp[i],x); double r=fn(tmp); std::swap(tmp[i],x); return r; };
是C++14版本。 C++11 版本将创建一个 tmp
变量并按值捕获它。
出于学习目的:
我正在创建一个小型数值方法库,我正在尝试实现渐变,目前我已经完成了 2D 渐变和 3D 渐变。但我想将其推广到更高的维度。
目前我有:
matrix<double> analysis::gradient_2D(std::function<double(double, double)> fn, double x, double y)
{
matrix<double> R(2, 1);
std::function<double(double)> fnX = [fn, y](double xVar){ return fn(xVar, y); };
std::function<double(double)> fnY = [fn, x](double yVar){ return fn(x, yVar); };
R(1, 1) = differentiateBest(fnX, x);
R(1, 2) = differentiateBest(fnY, y);
return R;
}
matrix<double> analysis::gradient_3D(std::function<double(double, double, double)> fn, double x, double y, double z)
{
matrix<double> R(3, 1);
std::function<double(double)> fnX = [fn, y, z](double xVar){ return fn(xVar, y,z); };
std::function<double(double)> fnY = [fn, x, z](double yVar){ return fn(x ,yVar, z); };
std::function<double(double)> fnZ = [fn, x, y](double zVar){ return fn(x, y, zVar); };
R(1, 1) = differentiateBest(fnX, x);
R(1, 2) = differentiateBest(fnY, y);
R(1, 3) = differentiateBest(fnZ, z);
return R;
}
// Where
double analysis::differentiateBest(std::function<double(double)> fn, double x)
{
return derivative_1_Richardson_6O(fn, x);
}
// For brevity , derivative_1_Richardson_6O also has the same input as differentiateBest
我知道它很冗长,但我喜欢它
问题 我想做的是创建一个
// What do I do at the ... ?
matrix<double> analysis::gradient_ND(std::function<double(...)> fn, matrix<double>)
这样我就可以通过任意输入的 std::function 说 N 我会通过 具有 N 个值的向量。
我将如何着手做这件事?如果答案太长,链接也将不胜感激。 谢谢你。
PS:我看到了一个使用模板的方法,但如果我在实现中使用模板,我将不得不将 .cpp 文件更改为其他文件,对吗?我想避免。如果使用模板是唯一的方法,那么我将不得不妥协。谢谢。
template<class T>
struct array_view {
T* b = nullptr; T* e = nullptr;
T* begin() const { return b; }
T* end() const { return e; }
size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front()const{return *begin(); }
T& back()const{return *std::prev(end()); }
T& operator[](size_t i)const{return begin()[i]; }
array_view( T* s, T* f ):b(s),e(f) {};
array_view() = default;
array_view( T* s, size_t l ):array_view(s, s+l) {}
using non_const_T = std::remove_const_t<T>;
array_view( std::initializer_list<non_const_T> il ):
array_view(il.begin(), il.end()) {}
template<size_t N>
array_view( T(&arr)[N] ):array_view(arr, N){}
template<size_t N>
array_view( std::array<T,N>&arr ):array_view(arr.data(), N){}
template<size_t N>
array_view( std::array<non_const_T,N> const&arr ):
array_view(arr.data(), N){}
template<class A>
array_view( std::vector<T,A>& v):
array_view(v.data(), v.size()){}
template<class A>
array_view( std::vector<non_const_T,A> const& v):
array_view(v.data(), v.size()){}
};
array_view
是对 T
的连续数组的非拥有视图。它具有来自无数连续容器的转换构造函数(如果 matrix
是连续的,则应编写 array_view
的转换器)。
然后:
matrix<double> analysis::gradient_ND(std::function<double(array_view<const double>)>, array_view<const double> pt)
合理。
使用 array_view
不会导致 .h
和 .cpp
代码拆分问题。所涉及的唯一模板要么是固定的(array_view
本身),要么是在构造 array_view
.
matrix<double> R(pt.size(), 1);
auto make_tmp = [pt]{
std::vector<double> tmp;
tmp.reserve(pt.size());
for (double x:pt)
tmp.push_back(x);
return tmp;
};
std::vector<std::function<double(double)>> partials;
partials.reserve(pt.size());
for (size_t i = 0; i < pt.size(); ++i) {
partials.push_back(
[&,i](double x){ auto tmp=make_tmp(); tmp[i]=x; return fn(tmp); };
);
}
for (size_t i = 0; i < pt.size(); ++i) {
R(1, i) = differentiateBest(partials[i], pt[i]);
}
return R;
请注意,实际上不需要创建 partials
的数组。你可以直接 differentiateBest
.
partials
重新分配每个呼叫时效率低下。如果您可以让重入不起作用(这通常是可以的),创建一个 tmp
并按值捕获它,并在每次调用 fn
后修改和恢复它,将提高性能。
[&,i,tmp=make_tmp()](double x){ std::swap(tmp[i],x); double r=fn(tmp); std::swap(tmp[i],x); return r; };
是C++14版本。 C++11 版本将创建一个 tmp
变量并按值捕获它。