我正在用C ++创建一种特定语言的解释器。创建解析器,实现范围解析等之后,我唯一的问题是实现动态类型的变量。
遵循一些常规建议,我创建了VarData和VarType结构:
union VarData{
int IntData;
char CharData;
double DoubleData;
};
enum class VarType {
Int,
Char,
Double
};
和可变结构(显然是不完整的):
struct Variable {
VarData data;
VarType type;
template<typename T>
void operator =(T val) {
std::string name = typeid(T).name();
if (name == "char") {
data.CharData = val;
type = VarType::Char;
}
else if (name == "int") {
data.IntData = val;
type = VarType::Int;
}
else if (name == "double") {
data.DoubleData = val;
type = VarType::Double;
}
}
};
这种实际的工作,例如在此示例代码中,所有分配的值均已正确存储:
int main() {
Variable a;
a = '5'; // a.type is now VarType::Char
a = 57; // a.type is now VarType::Int
a = 8.032; // a.type is now VarType::Double
}
我遇到的问题是,如果要使用Variable结构,我需要所有通用运算符(+,-,/,*等)的运算符重载,每个运算符都必须覆盖所有可能的对类型的Variable可以采取。例如,
Variable operator + (Variable& v1, Variable& v2) {
if (v1.type == VarType::Char && v2.type == VarType::Char)
//return Variable of type int
else if (v1.type == VarType::Double && v2.type == VarType::Int)
// return Variable of type double
else if (...)
}
还有其他方法(不涉及数百万个嵌套的if语句)吗?
抱歉,如果我的问题不清楚,我将很乐意提供其他解释。
答案 0 :(得分:2)
处理所有可能的类型组合的一种方法是使用double dispatch根据所涉及的类型执行操作。
双重调度将简化对要执行的操作变型的确定。这意味着很多,如果不是,则将过载超载或调度表的某种巧妙组合留给机械地寻找合适的操作的职责。但是,这并不是真正掌握组合爆炸的方法。
另一种更有效的方法是应用一些系统的类型提升规则。例如,如果要在一个运算中组合一个整数和一个浮点数,则需要在执行该运算之前将所有内容都转换为浮点数。
如果使用interpreter pattern,则在为相同类型的两个值调用适当的运算符重载之前,可以有template method pattern来管理类型提升。
无关但重要: 您需要注意,typeid()
不是标准化值。因此,“ int”,“ double”等都是不错的实现,但是其他编译器也可以使用其他字符串。这使您的代码不可移植