改造升压C ++凤凰防爆pression树 [英] Transforming a Boost C++ Phoenix Expression Tree
问题描述
在升压凤凰的文章,改造前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屋!