2013-03-05 28 views
5

Làm cách nào tôi cũng có thể bao gồm các phần chức năng trong một phép biến đổi biểu thức Tăng Phoenix?Chuyển đổi các hàm chức năng trong các biểu thức Boost Phoenix

Ví dụ, tôi đã xây dựng trên phần Chức năng Lazy của Boost Phoenix Starter Kit, và tạo ra một hàm addition lười biếng:

struct my_lazy_add_impl { 
    typedef int result_type; 
    template <typename T> 
    T operator()(T x, T y) const { return x+y; } 
}; 
phoenix::function<my_lazy_add_impl> my_add; 

sau đó tôi chuẩn bị một đơn giản cộng-to-trừ chuyển đổi từ một previous question, thể hiện ở đây :

struct invrt: 
    proto::or_< 
    proto::when< 
     proto::plus<proto::_, proto::_>, 
     proto::functional::make_expr<proto::tag::minus>(
     invrt(proto::_left), invrt(proto::_right) 
    ) 
    >, 
    proto::otherwise< 
     proto::nary_expr<proto::_, proto::vararg<invrt> > 
    > 
    > 
{}; 

Tuy nhiên, khi tôi áp dụng một biểu thức Phoenix lambda ngược, sử dụng my_add, để đối số của nó, như hình dưới đây, có vẻ như đảo ngược dự định đã không đạt được. Có cách nào được đề nghị để thực hiện các cuộc gọi hàm trong Phoenix, có thể tạo điều kiện cho các phép biến đổi như vậy không?

int main(int argc, char *argv[]) 
{ 
    auto f =   phoenix::lambda(_a = 0)[my_add(_1,_2)]; 
    auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]); 
    std::cout << f()(1,2) << std::endl; // 3 
    std::cout << g()(1,2) << std::endl; // 3 again; alas not -1 
    return 0; 
} 

Trả lời

3

Câu trả lời thực sự rất đơn giản và bạn sẽ tự đá. Chuyển đổi biểu thức bạn đã viết biết cách chuyển đổi nút dấu cộng thành nút trừ trừ. Nhưng không có nút dấu cộng nào trong biểu thức bạn đang truyền cho nó. Hãy nhìn lại:

auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]); 

Nút dấu cộng ở đâu? Để Proto (và Phoenix), my_add là mờ. Họ không biết có một sự bổ sung đang diễn ra bên trong đó. Làm sao họ có thể?

==== EDIT ====

Xem xét việc này thay vào đó, mà làm những gì bạn có ý định:

#include <iostream> 
#include <boost/phoenix.hpp> 
#include <boost/proto/proto.hpp> 
namespace proto = boost::proto; 
namespace phoenix = boost::phoenix; 
using namespace phoenix::arg_names; 
using namespace phoenix::local_names; 

auto const my_add = phoenix::let(_a = _1, _b = _2)[_a + _b]; 

struct invrt: 
    proto::or_< 
    proto::when< 
     proto::plus<proto::_, proto::_>, 
     proto::functional::make_expr<proto::tag::minus>(
     invrt(proto::_left), invrt(proto::_right) 
    ) 
    >, 
    proto::otherwise< 
     proto::nary_expr<proto::_, proto::vararg<invrt> > 
    > 
    > 
{}; 

int main() 
{ 
    auto f =   phoenix::lambda(_a = 0)[my_add(_1,_2)]; 
    auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]); 

    std::cout << f()(1,2) << std::endl; // 3 
    std::cout << g()(1,2) << std::endl; // -1, w00t! 
} 
+0

Thankyou. Tôi đã đoán đây là cách để làm điều đó, nhưng muốn có một số bảo đảm trước khi xây dựng trên ý tưởng. – user2023370

+0

p.s. Tôi đoán cơ thể 'let' cũng có thể là' _1 + _2'. – user2023370

+0

Tôi nghĩ/bạn sẽ thấy rằng trong các ngữ cảnh phức tạp hơn, bạn sẽ cần phải tạo ra một phạm vi mới cho các cơ quan chức năng của bạn; do đó là 'let'. Ít nhất, tôi dường như nhớ lại bài học này một cách khó khăn, nhưng đối với cuộc sống của tôi, tôi không thể nhớ tại sao. :-P –

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