本文介绍了模板上的 C++ 元函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些模板,如下所示,可以用来定义简单的表达式例如

I have some templates like the ones below that I can use to define simple expressionse.g.

Expr = 2

Expr, 1, 1> = x - 2.

我想定义一个元函数,它接受一个 Expr 并返回另一个 Expr,它是作为输入传递的那个的修改版本.输出将基于输入的模板参数,所以我想我必须定义多个专门用于不同输入的函数模板.最终我的目标是能够区分 Expr.

I want to define a meta-function that takes an Expr and returns another Expr that is a modified version of the one passed as input. The output will be based on the template arguments of the input so I guess I have to define multiple function templates that specialize different inputs. Eventually my goal is to be able to differentiate Expr's.

// 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);
    }
};

但是,我无法理解函数定义.到目前为止,我有:

However, I am having trouble wrapping my head around the function definition. So far I have:

template <template <ExprType eType, class Left, class Right, int coeff, int power> class E> struct ExprDerivative {
    static E derivative(E e){
        return e;
    }
};

我的方向是否正确?如何在模板上定义元函数?

Am I going in the right direction? How do I define a meta-function over templates?

推荐答案

您需要一个类型特征,它是一个以类型作为参数的函数.类型特征的定义看起来不像值上的函数(它们本质上是用函数式编程风格编写的,带有方程"),但它们的调用方式如您所料(func).

You want a type trait, which is a function with types as arguments. A type trait's definition looks nothing like a function on values (they're essentially written in a functional programming style, with "equations"), but they're called as you'd expect (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 不是常量;它们是 cx^n 形式的表达式.此外,它们还有多余的左右操作数.这样做会更好

However, I am worried about how you've written the Expr type in the first place. constants are not constants; they're expressions of the form cx^n. Also, they have extraneous left and right operands. It would be better to do this

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>>;

微分的结果确实简化了一点,但您可以编写另一个函数来清理:

The results of differentiation do end up a little less simplified, but you can write another function to clean up after:

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";
}

这篇关于模板上的 C++ 元函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-27 15:47
查看更多