模板上的 C++ 元函数
C++ meta-function over templates
我有一些模板,例如下面的模板,可以用来定义简单的表达式
例如
Expr<constant,int,int,1,1>
= 2
Expr<sub, Expr<constant,int,int,1,1>, Expr<constant,int,int,2,0>, 1, 1>
= x - 2.
我想定义一个元函数,它接受一个 Expr 和 returns 另一个 Expr,它是作为输入传递的那个的修改版本。输出将基于输入的模板参数,所以我想我必须定义多个专门用于不同输入的函数模板。最终我的目标是能够区分 Expr。
// the types of expressions (+,-,*, etc.)
enum ExprType { mul, divide, add, sub, constant};
// constant
template <ExprType eType, class Left, class Right, int coeff, int power> struct Expr {
static double eval(double x){
return coeff * std::pow(x, power);
}
};
//sub
template <class Left, class Right, int coeff, int power> struct Expr<sub, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) - Right::eval(x), power);
}
};
// add
template <class Left, class Right, int coeff, int power> struct Expr<add, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) + Right::eval(x), power);
}
};
但是,我无法理解函数定义。到目前为止我有:
template <template <ExprType eType, class Left, class Right, int coeff, int power> class E> struct ExprDerivative {
static E derivative(E e){
return e;
}
};
我的方向对吗?如何在模板上定义元函数?
不确定你想要什么...但确定你不能将模板参数作为函数参数传递。
在我看来,你的 ExprDerivative()
函数可以写成模板函数,允许从 e
参数中推导出模板模板和模板参数,如下所示
template <template <ExprType, typename, typename, int, int> class E,
ExprType eType, typename Left, typename Right,
int coeff, int power>
auto ExprDerivative (E<eType, Left, Right, coeff, power> e)
{ return e; }
注意,这样,参数 e
是 E<eType, Left, Right, coeff, power>
类型,而不是 E
类型(那不是类型)。
你可以使用它,举例如下
Expr<constant, int, int, 1, 1> e0;
auto e1 = ExprDerivative(e0);
你想要一个类型特征,它是一个以类型为参数的函数。类型特征的定义看起来一点也不像值上的函数(它们本质上是以函数式编程风格编写的,带有 "equations"),但它们的调用方式正如您所期望的那样(func<args>
)。
template<typename Differentiand> struct derivative;
// shorthand for calling the function: derivative_t<expr...>
template<typename Differentiand>
using derivative_t = typename derivative<Differentiand>::result;
// every "equation" is a specialization of derivative for a certain set of Exprs that defines the result as a member type
template<typename L, typename R, int coeff, int power>
struct derivative<Expr<constant, L, R, coeff, power>> { using result = Expr<constant, L, R, coeff*power, power - 1> };
// etc
但是,我很担心您最初是如何编写 Expr
类型的。 constant
s 不是常量;它们是 cx^n
形式的表达式。此外,它们还有无关的左右操作数。这样做会更好
struct variable {
static constexpr double eval(double x) { return x; }
};
template<int Value>
struct constant {
static constexpr double eval(double x) { return Value; }
};
template<typename Left, typename Right>
struct addition {
static constexpr double eval(double x) { return Left::eval(x) + Right::eval(x); }
};
template<typename Left, typename Right>
struct multiplication {
static constexpr double eval(double x) { return Left::eval(x) * Right::eval(x); }
};
template<typename Base, int Power>
struct exponentiation {
static double eval(double x) { return std::pow(Base::eval(x), Power); }
};
// no need to add these as "primitives"
template<typename Left, typename Right>
using subtraction = addition<Left, multiplication<constant<-1>, Right>>;
template<typename Left, typename Right>
using division = multiplication<Left, exponentiation<Right, -1>>;
微分的结果确实简化了一点,但你可以写另一个函数来清理:
template<>
struct derivative<variable> { using result = constant<1>; };
template<int Value>
struct derivative<constant<Value>> { using result = constant<0>; };
template<typename L, typename R>
struct derivative<addition<L, R>> { using result = addition<derivative_t<L>, derivative_t<R>>; };
template<typename L, typename R>
struct derivative<multiplication<L, R>> { using result = addition<multiplication<derivative_t<L>, R>, multiplication<L, derivative_t<R>>>; };
template<typename B, int N>
struct derivative<exponentiation<B, N>> { using result = multiplication<multiplication<constant<N>, exponentiation<B, N - 1>>, derivative_t<B>>; };
例如
int main() {
// y = (x^2 + 1)/x
// dy/dx = 1 - x^-2
// dy/dx(x = 2) = 1 - 1/4 = 0.75
std::cout << derivative_t<division<addition<exponentiation<variable, 2>, constant<1>>, variable>>::eval(2) << "\n";
}
我有一些模板,例如下面的模板,可以用来定义简单的表达式 例如
Expr<constant,int,int,1,1>
= 2
Expr<sub, Expr<constant,int,int,1,1>, Expr<constant,int,int,2,0>, 1, 1>
= x - 2.
我想定义一个元函数,它接受一个 Expr 和 returns 另一个 Expr,它是作为输入传递的那个的修改版本。输出将基于输入的模板参数,所以我想我必须定义多个专门用于不同输入的函数模板。最终我的目标是能够区分 Expr。
// the types of expressions (+,-,*, etc.)
enum ExprType { mul, divide, add, sub, constant};
// constant
template <ExprType eType, class Left, class Right, int coeff, int power> struct Expr {
static double eval(double x){
return coeff * std::pow(x, power);
}
};
//sub
template <class Left, class Right, int coeff, int power> struct Expr<sub, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) - Right::eval(x), power);
}
};
// add
template <class Left, class Right, int coeff, int power> struct Expr<add, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) + Right::eval(x), power);
}
};
但是,我无法理解函数定义。到目前为止我有:
template <template <ExprType eType, class Left, class Right, int coeff, int power> class E> struct ExprDerivative {
static E derivative(E e){
return e;
}
};
我的方向对吗?如何在模板上定义元函数?
不确定你想要什么...但确定你不能将模板参数作为函数参数传递。
在我看来,你的 ExprDerivative()
函数可以写成模板函数,允许从 e
参数中推导出模板模板和模板参数,如下所示
template <template <ExprType, typename, typename, int, int> class E,
ExprType eType, typename Left, typename Right,
int coeff, int power>
auto ExprDerivative (E<eType, Left, Right, coeff, power> e)
{ return e; }
注意,这样,参数 e
是 E<eType, Left, Right, coeff, power>
类型,而不是 E
类型(那不是类型)。
你可以使用它,举例如下
Expr<constant, int, int, 1, 1> e0;
auto e1 = ExprDerivative(e0);
你想要一个类型特征,它是一个以类型为参数的函数。类型特征的定义看起来一点也不像值上的函数(它们本质上是以函数式编程风格编写的,带有 "equations"),但它们的调用方式正如您所期望的那样(func<args>
)。
template<typename Differentiand> struct derivative;
// shorthand for calling the function: derivative_t<expr...>
template<typename Differentiand>
using derivative_t = typename derivative<Differentiand>::result;
// every "equation" is a specialization of derivative for a certain set of Exprs that defines the result as a member type
template<typename L, typename R, int coeff, int power>
struct derivative<Expr<constant, L, R, coeff, power>> { using result = Expr<constant, L, R, coeff*power, power - 1> };
// etc
但是,我很担心您最初是如何编写 Expr
类型的。 constant
s 不是常量;它们是 cx^n
形式的表达式。此外,它们还有无关的左右操作数。这样做会更好
struct variable {
static constexpr double eval(double x) { return x; }
};
template<int Value>
struct constant {
static constexpr double eval(double x) { return Value; }
};
template<typename Left, typename Right>
struct addition {
static constexpr double eval(double x) { return Left::eval(x) + Right::eval(x); }
};
template<typename Left, typename Right>
struct multiplication {
static constexpr double eval(double x) { return Left::eval(x) * Right::eval(x); }
};
template<typename Base, int Power>
struct exponentiation {
static double eval(double x) { return std::pow(Base::eval(x), Power); }
};
// no need to add these as "primitives"
template<typename Left, typename Right>
using subtraction = addition<Left, multiplication<constant<-1>, Right>>;
template<typename Left, typename Right>
using division = multiplication<Left, exponentiation<Right, -1>>;
微分的结果确实简化了一点,但你可以写另一个函数来清理:
template<>
struct derivative<variable> { using result = constant<1>; };
template<int Value>
struct derivative<constant<Value>> { using result = constant<0>; };
template<typename L, typename R>
struct derivative<addition<L, R>> { using result = addition<derivative_t<L>, derivative_t<R>>; };
template<typename L, typename R>
struct derivative<multiplication<L, R>> { using result = addition<multiplication<derivative_t<L>, R>, multiplication<L, derivative_t<R>>>; };
template<typename B, int N>
struct derivative<exponentiation<B, N>> { using result = multiplication<multiplication<constant<N>, exponentiation<B, N - 1>>, derivative_t<B>>; };
例如
int main() {
// y = (x^2 + 1)/x
// dy/dx = 1 - x^-2
// dy/dx(x = 2) = 1 - 1/4 = 0.75
std::cout << derivative_t<division<addition<exponentiation<variable, 2>, constant<1>>, variable>>::eval(2) << "\n";
}