改造升压C ++凤凰防爆pression树 [英] Transforming a Boost C++ Phoenix Expression Tree

查看:239
本文介绍了改造升压C ++凤凰防爆pression树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在升压凤凰的文章,改造前pression树,<一个href=\"http://www.boost.org/doc/libs/1_52_0/libs/phoenix/doc/html/phoenix/examples/transforming_the_ex$p$pssion_tree.html\"相对=nofollow>此处,一套定制的专业化的 invert_actions 类,用于反转二进制算术EX pressions。例如 A + B 变成 A-B ; A * B 变成 A / B ;和两个反之亦然。

这涉及到前pression树的递归遍历 - 但是,当遇到涉及没有明确的处理操作的前pression当这种遍历停止。例如, _1 + _2,_3 将成为 _1,_2 + _3 ,但 _1 + _1&放大器; _2 会留下,因为它是(有用于&放不处理; )。 让(_a = 1,_B = 2)[_a + _B] 也将保持不变。

我还以为这是按照预期的文章,但是看着在末尾列出的测试中,我看到如果_(_ 1 * _4)_ 2 - _3] 有望改变;与code供给(这里 ),我发现,事实并非如此。

我怎么能定义一个通用的升压凤凰前pression树转换适用于的所有的一组明确列出(n元)经营者;保留其他不变?

有些code可能是有用的。我想下面的C ++ 11 code(自动)输出 0 ,而不是 2 ;的没有的明确处理&安培; ,或其他任何运营商/声明。

 的#include&LT;&iostream的GT;
#包括LT&;升压/ phoenix.hpp&GT;
#包括LT&;升压/原/ proto.hpp&GT;使用名字空间boost;
使用原名称空间;
使用命名空间凤;
使用命名空间arg_names;结构invrt {
  模板&LT; typename的规则&GT;当结构:原:: _ {};
};模板&LT;&GT;
结构invrt ::当&LT;规则::加&GT;
  :原::调用&LT;
    原::功能:: make_expr&LT;原::标签::减去&GT;(
        评估(_Left,_context),评估(_right,_context)
    )
  &GT;
{};INT主(INT ARGC,CHAR *的argv [])
{
  汽车F = ::凤凰城的eval(_1 + _1&放大器; _2,make_context(MAKE_ENV(),invrt()));
  性病::法院LT&;&LT; F(1,2)&所述;&下;的std :: ENDL; //唉2而不是0
  返回0;
}


解决方案

这是你如何用直原始做到这一点:

 的#include&LT;&iostream的GT;
#包括LT&;升压/ phoenix.hpp&GT;
#包括LT&;升压/原/ proto.hpp&GT;
命名空间原=提振::原;
使用空间boost ::凤;
使用命名空间arg_names;结构invrt:
  原:: or_&LT;
    原::当&LT;
      //开启加节点为负
      原::加上&LT;原:: _,原:: _&gt;中
      原::功能:: make_expr&LT;原::标签::减去&GT;(
        invrt(原:: _左),invrt(原:: _右)
      )
    &gt;中
    原::否则&LT;
      //这个递归的儿童,invrt他们改造
      原:: nary_expr&LT;原:: _,原::可变参数&LT; invrt&GT; &GT;
    &GT;
  &GT;
{};INT主(INT ARGC,CHAR *的argv [])
{
  汽车F = invrt()(_ 1 + _1&安培; _2);
  原:: display_expr(F);
  性病::法院LT&;&LT; F(1,2)&所述;&下;的std :: ENDL;
  返回0;
}

凤凰分层一堆东西在原之上。我不知道凤凰:: EVAL 为什么你试过没有工作的语义。也许有人懂行的凤凰会附和

==== ====编辑

我想通了这个问题与凤凰的例子。它不是递归对非加的情况下。您code应该如下:

 的#include&LT;&iostream的GT;
#包括LT&;升压/ phoenix.hpp&GT;
#包括LT&;升压/原/ proto.hpp&GT;使用名字空间boost;
使用原名称空间;
使用命名空间凤;
使用命名空间arg_names;结构invrt {
  模板&LT; typename的规则&GT;
  当结构:
    // 注意!!!递归变换儿童和重组
    nary_expr&LT; _,可变参数&LT;原::当&LT; _,评估(_,_context)GT; &GT; &GT;
  {};
};模板&LT;&GT;
结构invrt ::当&LT;规则::加&GT; :
  原::调用&LT;
    原::功能:: make_expr&LT;原::标签::减去&GT;(
      评估(_Left,_context),评估(_right,_context)
    )
  &GT;
{};诠释的main()
{
  汽车F = ::凤凰城的eval(_1 + _1&放大器; _2,make_context(MAKE_ENV(),invrt()));
  display_expr(F);
  性病::法院LT&;&LT; F(1,2)&所述;&下;的std :: ENDL; //打印0好哇!
}

您是否认为简单或比直原解决方案更加复杂是你来决定。

In the Boost Phoenix article, "Transforming the Expression Tree", here, a set of specialisations of a custom invert_actions class, are used to invert binary arithmetic expressions. For example a+b becomes a-b; a*b becomes a/b; and vice versa for both.

This involves a recursive traversal of the expression tree - however, this traversal stops when an expression involving an operator not explicitly handled is encountered. For example, _1+_2-_3 will become _1-_2+_3, but _1+_1&_2 will stay as it is (there is no handler for &). let(_a = 1, _b = 2) [ _a+_b ] will also be left unchanged.

I had thought this was as intended by the article, but looking at the tests listed at the end, I see that if_(_1 * _4)[_2 - _3] is expected to change; with the code supplied (here), I find that it doesn't.

How then can I define a generic Boost Phoenix expression tree transform which applies to all of a set of explicitly listed (n-ary) operators; leaving the others unchanged?

Some code may be useful. I'd like the following C++11 code (auto) to output 0, and not 2; without explicitly handling the &, or any other operator/statement.

#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/proto/proto.hpp>

using namespace boost;
using namespace proto;
using namespace phoenix;
using namespace arg_names;

struct invrt {
  template <typename Rule> struct when : proto::_ {};
};

template <>
struct invrt::when<rule::plus>
  : proto::call<
    proto::functional::make_expr<proto::tag::minus>(
        evaluator(_left, _context), evaluator(_right, _context)
    )
  >
{};

int main(int argc, char *argv[])
{
  auto f = phoenix::eval( _1+_1&_2 , make_context(make_env(), invrt()) );
  std::cout << f(1,2) << std::endl; // Alas 2 instead of 0
  return 0;
}

解决方案

This is how you do it with straight Proto:

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

struct invrt:
  proto::or_<
    proto::when<
      // Turn plus nodes into minus
      proto::plus<proto::_, proto::_>,
      proto::functional::make_expr<proto::tag::minus>(
        invrt(proto::_left), invrt(proto::_right)
      )
    >,
    proto::otherwise<
      // This recurses on children, transforming them with invrt
      proto::nary_expr<proto::_, proto::vararg<invrt> >
    >
  >
{};

int main(int argc, char *argv[])
{
  auto f = invrt()(_1+_1&_2);
  proto::display_expr(f);
  std::cout << f(1,2) << std::endl;
  return 0;
}

Phoenix has layered a bunch of stuff on top of Proto. I don't know the semantics of pheonix::eval or why what you tried didn't work. Perhaps someone knowledgeable of Phoenix will chime in.

==== EDIT ====

I figured out the problem with the Phoenix example. It's not recursing for the non-plus case. Your code should be as follows:

#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/proto/proto.hpp>

using namespace boost;
using namespace proto;
using namespace phoenix;
using namespace arg_names;

struct invrt {
  template <typename Rule>
  struct when :
    // NOTE!!! recursively transform children and reassemble
    nary_expr<_, vararg<proto::when<_, evaluator(_, _context)> > >
  {};
};

template <>
struct invrt::when<rule::plus> :
  proto::call<
    proto::functional::make_expr<proto::tag::minus>(
      evaluator(_left, _context), evaluator(_right, _context)
    )
  >
{};

int main()
{
  auto f = phoenix::eval( _1+_1&_2 , make_context(make_env(), invrt()) );
  display_expr(f);
  std::cout << f(1,2) << std::endl; // Prints 0. Huzzah!
}

Whether you consider that simpler or more complicated than the straight Proto solution is for you to decide.

这篇关于改造升压C ++凤凰防爆pression树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆