【问题标题】:Transforming Function Bodies within Boost Phoenix Expressions在 Boost Phoenix 表达式中转换函数体
【发布时间】:2013-03-05 13:26:45
【问题描述】:

如何在 Boost Phoenix 表达式的转换中也包含函数体?

例如,我在Boost Phoenix Starter Kit的Lazy Functions部分构建,并创建了一个惰性添加函数:

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;

然后,我从previous question 准备一个简单的正负转换,如下所示:

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> >
    >
  >
{};

但是,当我将使用 my_add 的倒置 Phoenix lambda 表达式应用于其参数时,如下所示,似乎没有实现预期的倒置。有没有推荐的方法在 Phoenix 中实现函数调用,可以促进这种转换?

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;
}

【问题讨论】:

    标签: c++ templates boost boost-phoenix boost-proto


    【解决方案1】:

    答案真的很简单,你会踢自己的。您编写的表达式转换知道如何将加号node 转换为减号node。但是您传递给它的表达式中没有加号节点。再看一遍:

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

    加号节点在哪里?对于 Proto(和 Phoenix),my_add 是不透明的。他们不知道里面有一个额外的东西。他们怎么可能?

    ====编辑====

    请考虑一下,它会按照您的意愿行事:

    #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!
    }
    

    【讨论】:

    • 谢谢。我猜想这是这样做的方法,但在建立这个想法之前需要一些保证。
    • 附注我猜let 正文也可能是_1 + _2
    • 我 /think/ 你会发现在更复杂的上下文中你需要为你的函数体创建一个新的作用域;因此let。至少,我似乎回忆起这个教训是多么艰难,但对于我的一生,我已经不记得为什么了。 :-P
    • 是的,我也有同样的感觉;为什么不直接使用sequence (?),例如:auto const f2 = (stmt1,stmt2);。我倾向于lambda 而不是let 但我现在很惊讶地看到我使用范围的主要原因,他们将返回他们最后一个“声明”的值,也适用于sequence。唔。再次感谢,我会相信您的判断并暂时使用示波器。
    • 再一次,为了支持作用域,局部变量有时很好:)
    猜你喜欢
    • 1970-01-01
    • 2018-01-07
    • 2021-07-30
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多