2012-05-10 49 views

Trả lời

12

Nói chung bạn muốn một cách để thể hiện biểu tượng của bạn (tức là biểu mẫu mà mã hóa ví dụ 3 * x * x + 42), và một meta - chức năng có thể tính toán một đạo hàm. Hy vọng rằng bạn đủ quen thuộc với lập trình meta trong C++ để biết điều đó có nghĩa và đòi hỏi nhưng để cung cấp cho bạn một ý tưởng:

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

Sau đó bạn muốn trói hai phần (đại diện và tính toán) như vậy mà nó sẽ là thuận tiện để sử dụng. Ví dụ. derivative(3 * x * x + 42)(6) có thể có nghĩa là 'tính đạo hàm của 3 * x * x + 42 trong x ở 6'.

Tuy nhiên ngay cả khi bạn biết phải mất những gì để viết các mẫu biểu thức và những gì nó cần để viết một metaprogram trong C++ tôi sẽ không khuyên bạn nên đi theo nó theo cách này. Lập trình meta mẫu yêu cầu nhiều bản mẫu và có thể tẻ nhạt. Thay vào đó, tôi hướng dẫn bạn đến thư viện thiên tài Boost.Proto, được thiết kế chính xác để giúp viết EDSL (sử dụng các mẫu biểu thức) và hoạt động trên các mẫu biểu thức đó. Nó không nhất thiết phải dễ dàng để tìm hiểu để sử dụng nhưng tôi đã tìm thấy rằng việc học cách để đạt được cùng một điều mà không sử dụng nó là khó hơn. Dưới đây là một chương trình mẫu mà có thể trên thực tế hiểu và tính toán 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

Lưu ý: điều này không biên dịch trên studio hình ảnh 2015. –

Các vấn đề liên quan