2 ms·
For some of these, yes. For others, less so. Each one has their limitations. For the AstVisitor, you could make a templated class AstVisitor<T>. You would t
by MereInterest 11y ago
For some of these, yes. For others, less so. Each one has their limitations.
For the AstVisitor, you could make a templated class AstVisitor<T>. You would then derive AstVisitor<BoolLiteral> in order to have a class that only visits particular node types.
template<typename T>
class AstVisitor : public GenericAstVisitor {
// Implements GenericAstVisitor::Visit
virtual void Visit(AstNode* expr) {
T* t_expr = dynamic_cast<T*>(expr);
if(t_expr){
Visit(t_expr);
}
}
virtual void Visit(T* expr) = 0;
};
If you need to visit multiple node types, then you would need to head into variadic templates. Here, you would inherit from AstVisitor<BoolLiteral, NumLiteral>, then implement a visitor for each type.
template<typename... T>
class AstVisitor;
template<typename First, typename... Rest>
class AstVisitor<First, Rest...> : public AstVisitor<Rest...> {
virtual void Visit(AstNode* expr) {
First* f_expr = dynamic_cast<First*>(expr);
if(f_expr){
Visit(f_expr);
} else {
AstVisitor<Rest...>::Visit(expr);
}
}
virtual void Visit(First* expr) = 0;
};
template<>
class AstVisitor<> : GenericAstVisitor {
virtual void Visit(AstNode*) { }
};
For the enums and switch statements, I don't know of any way to get away from using macros. There have been some proposals for C++17 to include compile-time reflection, but until then, we're stuck with the macros.