我正在尝试基于std::variant
构建一个AST(我知道还有其他方法可以做到这一点,但我对围绕联合类型的方法特别感兴趣)。我有两个表达概念
- 叶表达式
- 递归表达式
我需要它才能使用std::variant
(因为它不允许递归类型)。叶表达式可能如下所示:
struct NameExpr
{
std::string name;
};
以及这样的回避表达式:
struct CallExpr
{
Expr target;
std::vector<Expr> args;
};
Expr
是所有表达式类型的总和:
struct BinaryExpr;
struct CallExpr;
using Expr = std::variant<
Recursive<BinaryExpr>,
Recursive<CallExpr>,
ConstantExpr,
NameExpr
>;
我必须转发声明我的递归表达式类型,因为它们的定义需要定义Expr
。Recursive
基本上是一个std::unique_ptr
。正如我所说,这个类只是为了打破Expr
内部的类型循环。
我的问题是,像std::unique_ptr
一样,我的Recursive
有一个非平凡的析构函数,它删除了指向实际表达式的指针。但是,由于我必须转发声明我的递归类型,因此在实例化模板时,所有使用Recursive
的类型都是不完整的,这反过来又会导致该实例化析构函数中的意外 (UB?) 行为。
我可以以某种方式解决此问题还是必须切换到其他设计?
(有点)地雷危险教育
添加一个~
并复制/移动 ctor 并分配。然后在定义所有内容后默认它们。
您可能还希望Expr
成为变体的薄包装器,以便您可以转发声明它。