递归表达式类中的 C++ 运算符重载

我有一个递归类 Expression 表示类似 bool 的表达式,例如:

(a & b) | (c & ~d)

请注意, Expression 处理一元和二元表达式。
基本上, Expression 应该遵循类似于 bool 表达式的 CFG。

我以这种方式设计了类(class):
class Expression {
public:
    Expression() = default;
    Expression(unique_ptr<Expression> lhs, unique_ptr<Expression> rhs,
        unique_ptr<IBinaryOperator> binop, unique_ptr<IUnaryOperator> unop);
    Expression operator^(Expression& that);
    Expression operator%(Expression& that);
    Expression operator|(Expression& that);
    Expression operator*(Expression& that);
    Expression operator+(Expression& that);
    Expression operator&(Expression& that);
    Expression operator>>(Expression& that);
    Expression operator!();
    Expression operator~();
    double Evaluate(double x);
    virtual ~Expression();
protected:
    unique_ptr<Expression> _lhs = nullptr;
    unique_ptr<Expression> _rhs = nullptr;
    unique_ptr<IBinaryOperator> _binop = nullptr;
    unique_ptr<IUnaryOperator> _unop = nullptr;
};

构造函数和二元运算符和一元运算符各一个的实现如下所示:
Expression::Expression(unique_ptr<Expression> lhs, unique_ptr<Expression> rhs, unique_ptr<IBinaryOperator> binop, unique_ptr<IUnaryOperator> unop) :
        _lhs(move(lhs)), _rhs(move(rhs)), _binop(move(binop)), _unop(move(unop)) {
}
Expression Expression::operator+(Expression&& that) {
    return Expression(unique_ptr<Expression>(this), unique_ptr<Expression>(&that), unique_ptr<IBinaryOperator>(new SumCoNorm), nullptr);
}
Expression Expression::operator~() {
    return Expression(nullptr, unique_ptr<Expression>(this), nullptr, unique_ptr<IUnaryOperator>(new Intensify));
}

该类无法编译
error: use of deleted function 'Fuzzy::Expression::Expression(const Fuzzy::Expression&)'
在每个重载运算符中(在 return 语句中)。
我觉得某些函数在内部试图使用不存在的 unique_ptr 的复制构造函数。我在这里和那里移动指针有什么问题吗?我在 GCCv4.8 中使用 C++11。

欢迎以任何方式对类界面的更改提出建议。我宁愿避免使用原始指针。

注意 :请不要建议使用解析器生成器等,例如 Boost.Spirit、YARD 或 YACC。该应用程序要求我从头开始实现。

最佳答案

从概念上讲,

return Expression(...);

创建一个新的 Expression 对象,然后将其复制或移动到返回值。在您的情况下,您没有移动构造函数(没有隐式移动构造函数,因为您有一个用户声明的析构函数)和一个已删除的复制构造函数,因此这是不可能的。

您可以使用
return {...};

避免复制/移动操作,或者您可以确保您有一个移动构造函数:
class Expression {
public:
    Expression() = default;
    Expression(Expression &&) = default;
...
};

附加说明,在 Ben Voigt 正确指出这使其编译但实际上不起作用的评论之后:
unique_ptr 仅适用于使用 new 分配的对象,除非您使用自定义删除器。在你的情况下,它只是行不通,你需要重新思考你的逻辑。

我认为您应该仅将 unique_ptr 作为实现细节保留,而不必让外部调用者担心。如果您确保您的 Expression 是可复制和可移动的,那么您应该没有问题根据需要从 Expression 中动态分配对象以存储为 _lhs_rhs 。以 std::vector<T> 为例,您不需要 new 来使用它,即使出于显而易见的原因,添加足够的元素在某些时候必然会开始需要动态内存分配。