c+中的运算符组合+; 我想知道C++中是否有一个优雅的解决方法来组成数学运算符。所谓运算符,我指的是如下内容: template<class H> class ApplyOp { H h; public: ApplyOp(){} ApplyOp(H h_i) : h(h_i) {} template<class argtype> double operator()(argtype f,double x){ return h(x)*f(x); } };
现在,我想组合操作符两次或更多次,即computec+中的运算符组合+; 我想知道C++中是否有一个优雅的解决方法来组成数学运算符。所谓运算符,我指的是如下内容: template<class H> class ApplyOp { H h; public: ApplyOp(){} ApplyOp(H h_i) : h(h_i) {} template<class argtype> double operator()(argtype f,double x){ return h(x)*f(x); } };,c++,c++11,functional-programming,C++,C++11,Functional Programming,现在,我想组合操作符两次或更多次,即computeA^2(f,2.0)。在上面的示例中,这将返回h(x)*h(x)*f(x)。请注意,这不是函数合成,即我不想计算A(A(f,2.0),2.0)。相反,考虑矩阵的计算能力:如果h(x)=M(矩阵),我想要M*M*..*M*x 我能够使用std::bind()实现A^2(但不是更高的幂!)的预期结果,如下所示: auto g = std::bind(&ApplyOp<Helper>::operator()<F>,&am
A^2(f,2.0)
。在上面的示例中,这将返回h(x)*h(x)*f(x)
。请注意,这不是函数合成,即我不想计算A(A(f,2.0),2.0)
。相反,考虑矩阵的计算能力:如果h(x)=M
(矩阵),我想要M*M*..*M*x
我能够使用std::bind()
实现A^2
(但不是更高的幂!)的预期结果,如下所示:
auto g = std::bind(&ApplyOp<Helper>::operator()<F>,&A,f,std::placeholders::_1);
从你们的问题中我可以理解,你们基本上是在试图定义
A^1(h, f, x) = h(x) * f(x)
A^n(h, f, x) = h(x) * A^(n-1)(h, f, x)
如果您愿意使用C++17,以下是您可以构建的内容:
#include <iostream>
#include <math.h>
template <int N>
struct apply_n_helper {
template <typename H, typename F>
auto operator()(H h, F f, double x) const {
if constexpr(N == 0) {
return f(x);
} else {
return h(x) * apply_n_helper<N - 1>()(h, f, x);
}
}
};
template <int N>
constexpr auto apply_n = apply_n_helper<N>();
int main() {
auto sqr = [](double x) { return x * x; };
auto exp_ = [](double x) { return exp(x); };
std::cout << apply_n<100>(sqr, exp_, 2.0) << '\n';
std::cout << apply_n<200>(sqr, exp_, 2.0) << '\n';
return 0;
}
实现这一点的另一种方法是有如下内容
#include <cmath>
#include <iostream>
template <size_t N, typename T>
T pow(const T& x) {
if constexpr(N == 0) {
return 1;
} else if (N == 1) {
return x;
} else {
return pow<N/2>(x) * pow<N - N/2>(x);
}
}
template <int N>
struct apply_n_helper {
template <typename H, typename F>
auto operator()(H h, F f, double x) const {
auto tmp = pow<N>(h(x));
return tmp * f(x);
}
};
template <int N>
constexpr auto apply_n = apply_n_helper<N>();
int main()
{
auto sqr = [](double x) { return x * x; };
auto exp_ = [](double x) { return exp(x); };
std::cout << apply_n<100>(sqr, exp_, 2.0) << '\n';
std::cout << apply_n<200>(sqr, exp_, 2.0) << '\n';
return 0;
}
#包括
#包括
模板
T功率(常数T&x){
如果constexpr(N==0){
返回1;
}else如果(N==1){
返回x;
}否则{
返回功率(x)*功率(x);
}
}
模板
结构应用辅助程序{
模板
自动运算符()(H,F,F,双x)常数{
自动tmp=功率(h(x));
返回tmp*f(x);
}
};
模板
constexpr auto apply_n=apply_n_helper();
int main()
{
auto sqr=[](双x){返回x*x;};
auto exp_U8;=[](双x){返回exp(x);};
根据我从你们的问题中所能理解的,你们基本上是在试图定义
A^1(h, f, x) = h(x) * f(x)
A^n(h, f, x) = h(x) * A^(n-1)(h, f, x)
如果您愿意使用C++17,以下是您可以构建的内容:
#include <iostream>
#include <math.h>
template <int N>
struct apply_n_helper {
template <typename H, typename F>
auto operator()(H h, F f, double x) const {
if constexpr(N == 0) {
return f(x);
} else {
return h(x) * apply_n_helper<N - 1>()(h, f, x);
}
}
};
template <int N>
constexpr auto apply_n = apply_n_helper<N>();
int main() {
auto sqr = [](double x) { return x * x; };
auto exp_ = [](double x) { return exp(x); };
std::cout << apply_n<100>(sqr, exp_, 2.0) << '\n';
std::cout << apply_n<200>(sqr, exp_, 2.0) << '\n';
return 0;
}
实现这一点的另一种方法是有如下内容
#include <cmath>
#include <iostream>
template <size_t N, typename T>
T pow(const T& x) {
if constexpr(N == 0) {
return 1;
} else if (N == 1) {
return x;
} else {
return pow<N/2>(x) * pow<N - N/2>(x);
}
}
template <int N>
struct apply_n_helper {
template <typename H, typename F>
auto operator()(H h, F f, double x) const {
auto tmp = pow<N>(h(x));
return tmp * f(x);
}
};
template <int N>
constexpr auto apply_n = apply_n_helper<N>();
int main()
{
auto sqr = [](double x) { return x * x; };
auto exp_ = [](double x) { return exp(x); };
std::cout << apply_n<100>(sqr, exp_, 2.0) << '\n';
std::cout << apply_n<200>(sqr, exp_, 2.0) << '\n';
return 0;
}
#包括
#包括
模板
T功率(常数T&x){
如果constexpr(N==0){
返回1;
}else如果(N==1){
返回x;
}否则{
返回功率(x)*功率(x);
}
}
模板
结构应用辅助程序{
模板
自动运算符()(H,F,F,双x)常数{
自动tmp=功率(h(x));
返回tmp*f(x);
}
};
模板
constexpr auto apply_n=apply_n_helper();
int main()
{
auto sqr=[](双x){返回x*x;};
auto exp_U8;=[](双x){返回exp(x);};
std::cout所以你希望能够对函数进行乘法。嗯,听起来不错。既然我们在那里,为什么不+
和-
和/
template<class F>
struct alg_fun;
template<class F>
alg_fun<F> make_alg_fun( F f );
template<class F>
struct alg_fun:F {
alg_fun(F f):F(std::move(f)){}
alg_fun(alg_fun const&)=default;
alg_fun(alg_fun &&)=default;
alg_fun& operator=(alg_fun const&)=default;
alg_fun& operator=(alg_fun &&)=default;
template<class G, class Op>
friend auto bin_op( alg_fun<F> f, alg_fun<G> g, Op op ) {
return make_alg_fun(
[f=std::move(f), g=std::move(g), op=std::move(op)](auto&&...args){
return op( f(decltype(args)(args)...), g(decltype(args)(args)...) );
}
);
}
template<class G>
friend auto operator+( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g), std::plus<>{} );
}
template<class G>
friend auto operator-( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g), std::minus<>{} );
}
template<class G>
friend auto operator*( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g),
std::multiplies<>{} );
}
template<class G>
friend auto operator/( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g),
std::divides<>{} );
}
template<class Rhs,
std::enable_if_t< std::is_convertible<alg_fun<Rhs>, F>{}, bool> = true
>
alg_fun( alg_fun<Rhs> rhs ):
F(std::move(rhs))
{}
// often doesn't compile:
template<class G>
alg_fun& operator-=( alg_fun<G> rhs )& {
*this = std::move(*this)-std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator+=( alg_fun<G> rhs )& {
*this = std::move(*this)+std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator*=( alg_fun<G> rhs )& {
*this = std::move(*this)*std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator/=( alg_fun<G> rhs )& {
*this = std::move(*this)/std::move(rhs);
return *this;
}
};
template<class F>
alg_fun<F> make_alg_fun( F f ) { return {std::move(f)}; }
auto identity = make_alg_fun([](auto&& x){ return decltype(x)(x); });
template<class X>
auto always_return( X&& x ) {
return make_alg_fun([x=std::forward<X>(x)](auto&&... /* ignored */) {
return x;
});
}
我们也可以有类型擦除alg funs
template<class Out, class...In>
using alg_map = alg_fun< std::function<Out(In...)> >;
可以更有效地完成
测试代码:
auto add_3 = make_alg_fun( [](auto&& x){ return x+3; } );
std::cout << (square * add_3)(3) << "\n";; // Prints 54, aka 3*3 * (3+3)
alg_map<int, int> f = identity;
std::cout << pow(f, 10)(2) << "\n"; // prints 1024
哪个组成(f,g)(x):=f(g(x))
你的代码现在真的变成了
alg_fun<Helper> h;
alg_fun<F> f;
auto result = pow( h, 10 )*f;
alg_fun h;
阿尔古芬夫;
自动结果=功率(h,10)*f;
这是h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*f(x)
。除了(有效版本)我只调用h
一次,然后将结果提高到10的幂次方。所以你希望能够对函数进行乘法。好吧,听起来不错。既然我们在那里,为什么不+
和-
和//code>
template<class F>
struct alg_fun;
template<class F>
alg_fun<F> make_alg_fun( F f );
template<class F>
struct alg_fun:F {
alg_fun(F f):F(std::move(f)){}
alg_fun(alg_fun const&)=default;
alg_fun(alg_fun &&)=default;
alg_fun& operator=(alg_fun const&)=default;
alg_fun& operator=(alg_fun &&)=default;
template<class G, class Op>
friend auto bin_op( alg_fun<F> f, alg_fun<G> g, Op op ) {
return make_alg_fun(
[f=std::move(f), g=std::move(g), op=std::move(op)](auto&&...args){
return op( f(decltype(args)(args)...), g(decltype(args)(args)...) );
}
);
}
template<class G>
friend auto operator+( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g), std::plus<>{} );
}
template<class G>
friend auto operator-( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g), std::minus<>{} );
}
template<class G>
friend auto operator*( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g),
std::multiplies<>{} );
}
template<class G>
friend auto operator/( alg_fun<F> f, alg_fun<G> g ) {
return bin_op( std::move(f), std::move(g),
std::divides<>{} );
}
template<class Rhs,
std::enable_if_t< std::is_convertible<alg_fun<Rhs>, F>{}, bool> = true
>
alg_fun( alg_fun<Rhs> rhs ):
F(std::move(rhs))
{}
// often doesn't compile:
template<class G>
alg_fun& operator-=( alg_fun<G> rhs )& {
*this = std::move(*this)-std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator+=( alg_fun<G> rhs )& {
*this = std::move(*this)+std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator*=( alg_fun<G> rhs )& {
*this = std::move(*this)*std::move(rhs);
return *this;
}
template<class G>
alg_fun& operator/=( alg_fun<G> rhs )& {
*this = std::move(*this)/std::move(rhs);
return *this;
}
};
template<class F>
alg_fun<F> make_alg_fun( F f ) { return {std::move(f)}; }
auto identity = make_alg_fun([](auto&& x){ return decltype(x)(x); });
template<class X>
auto always_return( X&& x ) {
return make_alg_fun([x=std::forward<X>(x)](auto&&... /* ignored */) {
return x;
});
}
我们也可以有类型擦除alg funs
template<class Out, class...In>
using alg_map = alg_fun< std::function<Out(In...)> >;
可以更有效地完成
测试代码:
auto add_3 = make_alg_fun( [](auto&& x){ return x+3; } );
std::cout << (square * add_3)(3) << "\n";; // Prints 54, aka 3*3 * (3+3)
alg_map<int, int> f = identity;
std::cout << pow(f, 10)(2) << "\n"; // prints 1024
哪个组成(f,g)(x):=f(g(x))
你的代码现在真的变成了
alg_fun<Helper> h;
alg_fun<F> f;
auto result = pow( h, 10 )*f;
alg_fun h;
阿尔古芬夫;
自动结果=功率(h,10)*f;
它是h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*h(x)*f(x)
。除了(在高效版本中)我只调用h
一次,然后将结果提高到10的幂。我的意思是你可以使用另一个类:
template <typename T, std::size_t N>
struct Pow
{
Pow(T t) : t(t) {}
double operator()(double x) const
{
double res = 1.;
for (int i = 0; i != N; ++i) {
res *= t(x);
}
return res;
}
T t;
};
模板
结构功率
{
Pow(T):T(T){
双运算符()(双x)常量
{
双精度=1。;
对于(int i=0;i!=N;++i){
res*=t(x);
}
返回res;
}
T;
};
和使用
ApplyOp B(h);
而不是ApplyOp A(h);
我的意思是你可以使用另一个类:
template <typename T, std::size_t N>
struct Pow
{
Pow(T t) : t(t) {}
double operator()(double x) const
{
double res = 1.;
for (int i = 0; i != N; ++i) {
res *= t(x);
}
return res;
}
T t;
};
模板
结构功率
{
Pow(T):T(T){
双运算符()(双x)常量
{
双精度=1。;
对于(int i=0;i!=N;++i){
res*=t(x);
}
返回res;
}
T;
};
和使用
ApplyOp B(h);
而不是ApplyOp A(h);
尝试使用模板专门化
#include<iostream>
#include<math.h>
#include<functional> //For std::bind
template<class H>
class ApplyOp {
H h;
public:
ApplyOp(){}
ApplyOp(H h_i) : h(h_i) {}
template<class argtype>
double operator()(argtype f,double x){
return h(x)*f(x);
}
};
struct Helper{
Helper(){}
double operator()(double x){return x*x;}
};
struct F{
F(){}
double operator()(double x){return exp(x);}
};
// C++ doesn't permit recursive "partial specialization" in function
// So, make it a struct instead
template<typename T, typename U, typename W, int i>
struct Binder {
auto binder(U b, W c) {
// Recursively call it with subtracting i by one
return [&](T x){ return b(Binder<T, U, W, i-1>().binder(b, c), x); };
}
};
// Specialize this "struct", when i = 2
template<typename T, typename U, typename W>
struct Binder<T, U, W, 2> {
auto binder(U b, W c) {
return [&](T x){ return b(c, x); };
}
};
// Helper function to call this struct (this is our goal, function template not
// struct)
template<int i, typename T, typename U, typename W>
auto binder(U b, W d) {
return Binder<T, U, W, i>().binder(b, d);
}
int main()
{
Helper h;
F f;
ApplyOp<Helper> A(h);
std::cout<<"A(f,2.0) = "<<A(f,2.0)<<std::endl; //Returns 2^2*exp(2) = 29.5562...
// We don't need to give all the template parameters, C++ will infer the rest
auto g = binder<2, double>(A, f);
std::cout<<"A^2(f,2.0) = "<<A(g,2.0) <<std::endl; //Returns 2^4*exp(2) = 118.225...
auto g1 = binder<3, double>(A, f);
std::cout<<"A^3(f,2.0) = "<<A(g1,2.0) <<std::endl; //Returns 2^6*exp(2) = 472.2
auto g2 = binder<4, double>(A, f);
std::cout<<"A^4(f,2.0) = "<<A(g2,2.0) <<std::endl; //Returns 2^8*exp(2) = 1891.598...
return 0;
}
#包括
#包括
#include//For std::bind
模板
类应用程序{
H;
公众:
ApplyOp(){}
ApplyOp(hui):H(hui){
模板
双运算符()(argtype f,double x){
返回h(x)*f(x);
}
};
结构辅助程序{
Helper(){}
双运算符()(双x){return x*x;}
};
结构F{
F(){}
双运算符()(双x){return exp(x);}
};
//C++不允许函数中递归的“部分特化”
//因此,将其改为结构
模板
结构粘合剂{
自动装订机(U b、W c){
//递归地用i减去1来调用它
return[&](tx){返回b(Binder().Binder(b,c,x);};
}
};
//当i=2时,专门化此“结构”
模板
结构粘合剂{
自动装订机(U b、W c){
return[&](tx){return b(c,x);};
}
};
//帮助函数调用此结构(这是我们的目标,函数模板不是
//结构)
模板
自动装订机(U b,W d){
返回活页夹()。活页夹(b,d);
}
int main()
{
助手h;
F;
苹果酸A(h);
std::cout试试这个,使用模板专门化
#include<iostream>
#include<math.h>
#include<functional> //For std::bind
template<class H>
class ApplyOp {
H h;
public:
ApplyOp(){}
ApplyOp(H h_i) : h(h_i) {}
template<class argtype>
double operator()(argtype f,double x){
return h(x)*f(x);
}
};
struct Helper{
Helper(){}
double operator()(double x){return x*x;}
};
struct F{
F(){}
double operator()(double x){return exp(x);}
};
// C++ doesn't permit recursive "partial specialization" in function
// So, make it a struct instead
template<typename T, typename U, typename W, int i>
struct Binder {
auto binder(U b, W c) {
// Recursively call it with subtracting i by one
return [&](T x){ return b(Binder<T, U, W, i-1>().binder(b, c), x); };
}
};
// Specialize this "struct", when i = 2
template<typename T, typename U, typename W>
struct Binder<T, U, W, 2> {
auto binder(U b, W c) {
return [&](T x){ return b(c, x); };
}
};
// Helper function to call this struct (this is our goal, function template not
// struct)
template<int i, typename T, typename U, typename W>
auto binder(U b, W d) {
return Binder<T, U, W, i>().binder(b, d);
}
int main()
{
Helper h;
F f;
ApplyOp<Helper> A(h);
std::cout<<"A(f,2.0) = "<<A(f,2.0)<<std::endl; //Returns 2^2*exp(2) = 29.5562...
// We don't need to give all the template parameters, C++ will infer the rest
auto g = binder<2, double>(A, f);
std::cout<<"A^2(f,2.0) = "<<A(g,2.0) <<std::endl; //Returns 2^4*exp(2) = 118.225...
auto g1 = binder<3, double>(A, f);
std::cout<<"A^3(f,2.0) = "<<A(g1,2.0) <<std::endl; //Returns 2^6*exp(2) = 472.2
auto g2 = binder<4, double>(A, f);
std::cout<<"A^4(f,2.0) = "<<A(g2,2.0) <<std::endl; //Returns 2^8*exp(2) = 1891.598...
return 0;
}
#包括
#包括
#include//For std::bind
模板
类应用程序{
H;
公众:
ApplyOp(){}
ApplyOp(hui):H(hui){
模板
双运算符()(argtype f,double x){
返回h(x)*f(x);
}
};
结构辅助程序{
Helper(){}
双运算符()(双x){return x*x;}
};
结构F{
F(){}
双运算符()(双x){return exp(x);}
};
//C++不允许函数中递归的“部分特化”
//因此,将其改为结构
模板
结构粘合剂{
自动装订机(U b、W c){