【问题标题】:Boost recursive_wrapper recursion提升 recursive_wrapper 递归
【发布时间】:2016-03-09 07:30:30
【问题描述】:

我有 binop 结构,它表示 2 个相同类型的表达式的二元运算。 我有 2 种不同类型的表达式:arithmetic_exprlogical_expr 定义为 boost::variant。

目标是让binop 有两个字段:rhslhs 这些表达式的具体类型。如何做到这一点?

这是我目前想出的:

template <typename expr_type, typename tag> struct binop;

struct op_plus  {};
typedef boost::variant<
            int,
            boost::recursive_wrapper<binop<arithmetic_expr, op_plus>>  // <-- fails here 'arithmetic_expr': undeclared identifier
    > arithmetic_expr;


struct op_and {};
typedef boost::variant<
            bool,
            boost::recursive_wrapper<binop<logical_expr, op_and>>
    > logical_expr;


template <typename expr_type, typename tag>
struct binop
{
    explicit binop(const expr_type& l, const expr_type& r) : lhs(l), rhs(r) { }
    expr_type lhs, rhs;
};

一个用例示例是:

(((1 + 2) /* arithmetic_expr */ + 3) /* arithmetic_expr */ AND (4 + 5) /* arithmetic_expr */) /* logical_expr */

【问题讨论】:

  • 我们可以从在某处定义算术表达式开始。我在上面的代码中看不到它的定义。
  • 如果我将算术表达式声明为结构,编译器会抱怨变体声明与结构不兼容..
  • 您想在变体中存储绑定值,还是只存储操作?即变体是设计成一个完整的表达式还是一个特定领域的语言程序,可以从其他地方获取输入?你能发布一个用例的例子吗?

标签: c++ boost


【解决方案1】:

这样的?

#include <iostream>
#include <utility>
#include <boost/variant.hpp>

// identity evaluation
int evaluate(int i) { return i; }

// introduce the concep of binary op
template<class ActualOp> struct binary_op;

using add = binary_op<std::plus<int>>;
using subtract = binary_op<std::minus<int>>;
using times = binary_op<std::multiplies<int>>;

// our variant
using expression = boost::variant
<
int,
boost::recursive_wrapper<add>,
boost::recursive_wrapper<subtract>,
boost::recursive_wrapper<times>
>;

// overload for evaluating the variant
struct compute : boost::static_visitor<int>
{
    template<class T> int operator()(const T& t) const { return evaluate(t); }
};


int evaluate(const expression& e)
{
    return boost::apply_visitor(compute(), e);
};

// evaluate the binary op
template<class ActualOp>
struct binary_op
{
    binary_op(expression l, expression r)
    : _l(std::move(l)), _r(std::move(r))
    {}

    ActualOp _op;
    expression _l, _r;
};
template<class Op>
int evaluate(const binary_op<Op>& o) {
    return o._op(evaluate(o._l), evaluate(o._r));
}

int main()
{
    using namespace std;


    expression e = add(6, times(3,subtract(7,2)));

    cout << evaluate(e) << endl;
    return 0;
}

预期输出:

21

【讨论】:

  • 这一切都很好,但是说我有using bool_expression = boost::variant&lt;bool, boost::recursive_wrapper&lt;and&gt;&gt;。如何将 binary_op.expression 模板化为 bool_expression ?这就是问题
  • 您需要添加另一个包含 bool_expression 和 int_expression 的变体类型。您可能还希望转换函数在它们之间进行转换。基本上,您正在构建一个 EBNF,因此您需要其中的每个复合术语都有一个变体。祝你好运! :)
  • 没错,已经试过了,但我想避免这两个表达式的包装变体..不确定这是否可能
  • 我认为不是。
  • 我不认为 EBNF 意味着你认为它的意思:) 但是,是的,请先考虑语法。构建相应的 AST。简单!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多