我正在尝试实现访问 AST 的访问者模式。我定义了一个ASTNode
,它可以接受Visitor
,并允许访问者访问自身。下面的示例包含 Visitor 和 ASTNode 各一个具体实现。
class ASTNode;
template <class P, class R>
class Visitor {
public:
virtual ~Visitor() {}
virtual R visit(ASTNode& node, P p) const = 0;
};
class ASTNode {
public:
virtual ~ASTNode() {}
template <class P, class R>
virtual R accept(Visitor<R, P>& v, P p) {
return v.visit(*this);
}
};
class Roman : public ASTNode {
public:
Roman(Numeral n, optional<Accidental> a) : numeral(n), alteration(a) {};
const Numeral numeral;
const optional<Accidental> alteration;
};
class ToStringVisitor : public Visitor<string, int> {
virtual string visit(Roman& node, int param) {
string result = NumeralStrings[node.numeral];
if (node.alteration.has_value()) result = accidentalToString(node.alteration.value()) + result;
return result;
}
};
然后,我可以使用如下方式遍历 AST:
Roman r;
ToStringVisitor tsv;
// ...
return r.accept(tsv, 42);
正如您所看到的,我正在尝试使用模板来允许参数和返回值。但是,我收到编译器错误:
error: templates may not be 'virtual'
virtual R accept(Visitor<R, P>& v, P p) {
我对为什么这是一个错误有一个模糊的理解。但是,我怎样才能合法地实现这一点呢?
编辑:我认为这不是 this question 的重复项,因为我还尝试让accept返回模板类型。
最佳答案
访问/接受函数不应接受额外参数或返回 void
以外的任何内容。具体访问者对象在构造时获取额外的数据。它还可以存储您想要从方法返回的任何结果。这是沼泽标准构造,不需要任何模板。
class NodeVisitor {
virtual void visit (Roman*) = 0;
...
};
class ToStringVisitor : public NodeVisitor {
ToStringVisitor (int param) : param(param) {}
void visit (Roman* r) {
result = ...;
}
...
int param;
std::string result;
};
关于c++ - 虚拟模板函数: implementing the Visitor pattern with parameters,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45749266/