在 C++ 中创建动态数据类型
Creating dynamic data-type in C++
我正在用 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 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 语句)方法来做到这一点?
抱歉,如果我的问题不是很清楚,我很乐意提供额外的解释。
处理所有可能的不同类型组合的一种方法是使用 double dispatch 根据涉及的类型执行操作。
双重分派将简化对要执行的操作变体的确定。这意味着很多(如果更少的话),将重载覆盖或调度 table 机械地找到 suitable 操作的职责留给一些巧妙的组合。不过,也算不上组合爆的真正掌握。
另一种更有效的方法是应用一些系统类型的提升规则。例如,如果你想在一个操作中组合一个整数和一个浮点数,你会在执行操作之前将所有内容都转换为浮点数。
如果在为相同类型的两个值调用 suitable 运算符重载之前使用 interpreter pattern, you could have a template method pattern 管理类型提升。
无关但重要: 您需要注意 typeid()
不是标准值。所以 "int"、"double" 等...是一个很好的实现,但其他字符串可能会用于其他编译器。这使您的代码非 portable
我正在用 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 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 语句)方法来做到这一点?
抱歉,如果我的问题不是很清楚,我很乐意提供额外的解释。
处理所有可能的不同类型组合的一种方法是使用 double dispatch 根据涉及的类型执行操作。
双重分派将简化对要执行的操作变体的确定。这意味着很多(如果更少的话),将重载覆盖或调度 table 机械地找到 suitable 操作的职责留给一些巧妙的组合。不过,也算不上组合爆的真正掌握。
另一种更有效的方法是应用一些系统类型的提升规则。例如,如果你想在一个操作中组合一个整数和一个浮点数,你会在执行操作之前将所有内容都转换为浮点数。
如果在为相同类型的两个值调用 suitable 运算符重载之前使用 interpreter pattern, you could have a template method pattern 管理类型提升。
无关但重要: 您需要注意 typeid()
不是标准值。所以 "int"、"double" 等...是一个很好的实现,但其他字符串可能会用于其他编译器。这使您的代码非 portable