我正在尝试将我之前用函数式语言 (OCaml) 编写的一些代码重写为 C++。
我的问题可以简化为:
- 我有一堆价值观
- 值可以是变体类型(因此是一组不同类型的值,例如
int
,float
,std::string
,std::list
等等) - 我想定义对值起作用的运算符(例如,弹出两个值并推动它们之和的加法运算)
- 一些运算符的行为会根据堆栈上的类型而有所不同,理想情况下,一些运算符甚至会根据类型更改参数的数量(一个简单的例子:加法运算符可以弹出一个值,如果它是 a
std::list
then push 运算符应用于所有列表的值,否则弹出另一个值并在它们都是浮动的情况下进行加法)
到目前为止,我已经能够通过使用模板使其工作,例如。
class Value
{
public:
Value(Type type) : type(type) { }
virtual string svalue() const = 0;
virtual string lvalue();
virtual bool equals(Value *value) const = 0;
virtual Value* clone() const = 0;
const Type type;
virtual ~Value() { };
}
template <class T>
class TValue : public Value
{
protected:
T value;
public:
TValue(Type type, T value) : Value(type), value(value) {}
void set(T value) { this->value = value; }
T get() const { return this->value; }
};
class Int : public TValue<int>
{
private:
public:
Int(int value) : TValue<int>(TYPE_INT, value) { };
virtual string svalue() const;
virtual bool equals(Value *value) const { return this->value == ((TValue<int>*)value)->get(); }
virtual Value *clone() const { return new Int(value); }
};
然后通过做来解释运算符
Value *v1, *v2,
case OP_PLUS:
{
if (vm->popTwo(&v1, &v2))
{
switch (v1->type << 4 | v2->type)
{
case TYPES(TYPE_INT, TYPE_INT): vm->push(new Int(((Int*)v1)->get() + ((Int*)v2)->get())); break;
case TYPES(TYPE_FLOAT, TYPE_INT): vm->push(new Float(((Float*)v1)->get() + ((Int*)v2)->get())); break;
case TYPES(TYPE_INT, TYPE_FLOAT): vm->push(new Float(((Int*)v1)->get() + ((Float*)v2)->get())); break;
case TYPES(TYPE_FLOAT, TYPE_FLOAT): vm->push(new Float(((Float*)v1)->get() + ((Float*)v2)->get())); break;
}
}
break;
}
现在,这行得通,但我不喜欢这种方法,因为它听起来很笨拙,需要大量类型转换,而且一点也不优雅(与我的功能实现相比)。我开始研究boost库,看看我是否能找到一种更好的方法来管理一切,在开始之前我试图定义一种不同的方式来定义运算符,例如
template <Opcode T, class X, class A>
class Unary
{
public:
static A* ptr(X* x)
{
cout << "Missing instruction!" << endl;
return NULL;
};
};
template <>
class Unary<OP_MINUS, Float, Float>
{
public:
static Float *ptr(Float *x) { return new Float(-x->get()); };
};
这样我就能做到
Float *a = new Float(10);
Float *r = Unary<OP_MINUS, Float, Float>::ptr(f);
这可行,但我仍然无法看到我应该如何以通用方式管理它,以便我可以根据堆栈上找到的内容和使用的运算符调用正确的函数。
boost会以某种方式帮助我吗?我想要的是一个同时类型安全和优雅的解决方案,但是 boost 有这么多不同的库,我很难理解要寻找什么。如果我缺少一些更简单的东西,我不需要使用它,我没想到在为这种任务放弃功能语言时会发现这么多困难。