2012-05-10 9 views

Respuesta

12

En general te gustaría una manera de representar los símbolos (es decir, las expresiones plantillas que codifican por ejemplo 3 * x * x + 42), y un meta -función que puede calcular una derivada. Es de esperar que eres lo suficientemente familiarizado con metaprogramming en C++ para saber lo que significa e implica, sino para darle una idea:

// This should come from the expression templates 
template<typename Lhs, typename Rhs> 
struct plus_node; 

// Metafunction that computes a derivative 
template<typename T> 
struct derivative; 

// derivative<foo>::type is the result of computing the derivative of foo 

// Derivative of lhs + rhs 
template<typename Lhs, typename Rhs> 
struct derivative<plus_node<Lhs, Rhs> > { 
    typedef plus_node< 
     typename derivative<Lhs>::type 
     , typename derivative<Rhs>::type 
    > type; 
}; 

// and so on 

A continuación, tendría atar las dos partes (representación y cálculo) de tal manera que sería conveniente de usar P.ej. derivative(3 * x * x + 42)(6) podría significar 'calcular la derivada de 3 * x * x + 42 en x a 6'.

Sin embargo, incluso si sabe lo que se necesita para escribir plantillas de expresión y lo que se necesita para escribir un metaprograma en C++, no recomendaría hacerlo de esta manera. La metaprogramación de plantillas requiere una gran repetición y puede ser tediosa. En su lugar, lo dirijo a la genio Boost.Proto biblioteca, que está diseñada precisamente para ayudar a escribir EDSL (utilizando plantillas de expresión) y operar en esas plantillas de expresión. No es necesariamente fácil de aprender a usar, pero he descubierto que aprender a lograr lo mismo sin usarlo es más difícil. Aquí está un ejemplo de programa que puede, de hecho, entender y calcular derivative(3 * x * x + 42)(6):

#include <iostream> 

#include <boost/proto/proto.hpp> 

using namespace boost::proto; 

// Assuming derivative of one variable, the 'unknown' 
struct unknown {}; 

// Boost.Proto calls this the expression wrapper 
// elements of the EDSL will have this type 
template<typename Expr> 
struct expression; 

// Boost.Proto calls this the domain 
struct derived_domain 
: domain<generator<expression>> {}; 

// We will use a context to evaluate expression templates 
struct evaluation_context: callable_context<evaluation_context const> { 
    double value; 

    explicit evaluation_context(double value) 
     : value(value) 
    {} 

    typedef double result_type; 

    double operator()(tag::terminal, unknown) const 
    { return value; } 
}; 
// And now we can do: 
// evalutation_context context(42); 
// eval(expr, context); 
// to evaluate an expression as though the unknown had value 42 

template<typename Expr> 
struct expression: extends<Expr, expression<Expr>, derived_domain> { 
    typedef extends<Expr, expression<Expr>, derived_domain> base_type; 

    expression(Expr const& expr = Expr()) 
     : base_type(expr) 
    {} 

    typedef double result_type; 

    // We spare ourselves the need to write eval(expr, context) 
    // Instead, expr(42) is available 
    double operator()(double d) const 
    { 
     evaluation_context context(d); 
     return eval(*this, context); 
    } 
}; 

// Boost.Proto calls this a transform -- we use this to operate 
// on the expression templates 
struct Derivative 
: or_< 
    when< 
     terminal<unknown> 
     , boost::mpl::int_<1>() 
    > 
    , when< 
     terminal<_> 
     , boost::mpl::int_<0>() 
    > 
    , when< 
     plus<Derivative, Derivative> 
     , _make_plus(Derivative(_left), Derivative(_right)) 
    > 
    , when< 
     multiplies<Derivative, Derivative> 
     , _make_plus(
      _make_multiplies(Derivative(_left), _right) 
      , _make_multiplies(_left, Derivative(_right)) 
     ) 
    > 
    , otherwise<_> 
> {}; 

// x is the unknown 
expression<terminal<unknown>::type> const x; 

// A transform works as a functor 
Derivative const derivative; 

int 
main() 
{ 
    double d = derivative(3 * x * x + 3)(6); 
    std::cout << d << '\n'; 
} 
+0

Nota: esto no se compila en Visual Studio 2015. –