我正在构建解释器,并尝试避免在实现内置函数时遇到一些样板。我可以通过使用模板来做到这一点。
以该基本模板为例:
template<ast::builtin_type T>
class builtin_procedure abstract : public builtin_procedure_symbol
{
using arg_traits = builtin_type_traits<T>;
protected:
builtin_procedure(const symbol_identifier& identifier): builtin_procedure_symbol(identifier)
{
this->register_param(arg_traits::param_id(), T);
}
/**
* The actual implementation of the built-in function
*/
virtual void invoke_impl(typename arg_traits::builtin_type) = 0;
public:
void invoke(scope_context& procedure_scope) override
{
auto raw_arg = procedure_scope.memory->get(procedure_scope.symbols.get(arg_traits::param_id()));
this->invoke_impl(arg_traits::get_from_expression(raw_arg));
}
};
要实现采用字符串的内置函数,我只需要这样做:
class builtin_procedure_writeln final : public builtin_procedure<ast::builtin_type::string>
{
protected:
void invoke_impl(arg_traits::builtin_type arg) override;
public:
builtin_procedure_writeln();
}; /* Implementation in cpp file */
非常方便,我只需要实现虚拟的invoke_impl
方法即可。
我正在努力解决,要使用可变数量的模板参数来实现此目标,因此,如果要在派生实现中支持2、3或更多参数,则不必重复模板定义。如下面的示例。
这将是上面的模板,以支持第二个模板参数:template<ast::builtin_type T1, ast::builtin_type T2>
class builtin_procedure abstract : public builtin_procedure_symbol
{
using arg1_traits = builtin_type_traits<T1>;
using arg2_traits = builtin_type_traits<T2>;
protected:
builtin_procedure(const symbol_identifier& identifier): builtin_procedure_symbol(identifier)
{
this->register_param(arg_traits::param_id(1), T1);
this->register_param(arg_traits::param_id(2), T2);
}
/**
* The actual implementation of the built-in function
*/
virtual void invoke_impl(typename arg1_traits::builtin_type, typename arg2_traits::builtin_type) = 0;
public:
void invoke(scope_context& procedure_scope) override
{
auto raw_arg1 = procedure_scope.memory->get(procedure_scope.symbols.get(arg1_traits::param_id()));
auto raw_arg2 = procedure_scope.memory->get(procedure_scope.symbols.get(arg2_traits::param_id()));
this->invoke_impl(arg1_traits::get_from_expression(raw_arg1), arg2_traits::get_from_expression(raw_arg2));
}
};
我知道,基本上可以通过模板递归来迭代每个模板参数,以执行所需的操作,但是虚拟invoke_impl
方法的定义呢?每个参数都是从traits结构派生的,使用模板递归似乎也无法调用该方法本身。[((如果(可能))如何使用可变参数模板在此基类上允许可变数量的参数,而不是仅使用更多模板参数复制/粘贴此基类?
ast::builtin_type
切换为int
,但我认为您可以轻松地将其反转。以下编译(但显然不链接,^^)。template<int i>
struct builtin_traits {
static int param_id(int) { return i;}
using builtin_type = int;
};
class builtin_procedure_symbol {
void register_param(int, int);
};
int get(int); // my replacement for procedure_scope.memory->get(procedure_scope.symbols.get
template<int... Ts>
class builtin_procedure : builtin_procedure_symbol{
builtin_procedure(): builtin_procedure_symbol()
{
((void) this->register_param(builtin_traits<Ts>::param_id(1), Ts), ... );
}
virtual void invoke_impl(typename builtin_traits<Ts>::builtin_type...) = 0;
void invoke()
{
auto f = [&](const auto& arg) {
auto raw_arg = get(builtin_traits<arg>::param_id());
return builtin_traits<arg>::get_from_expression(raw_arg);
};
this->invoke_impl(f(Ts)...);
}
};
希望对您有所帮助。如果不清楚,请询问。