根据c++中的特定类型执行代码
Executing code according to specific types in C++
我正在尝试将我以前用函数式语言(OCaml)编写的一些代码重写为c++。
我的问题可以缩短为:
- 我有一堆值
- 一个值可以是一个可变类型(即一组不同类型的值,例如
int
,float
,std::string
,std::list
等等) - 我想定义对值工作的操作符(例如,弹出两个值并推动它们之和的加法操作)
- 一些操作符根据在堆栈上找到的类型表现不同,理想情况下,一些操作符甚至根据类型改变参数的数量(一个简单的例子:加法操作符可以弹出一个值,如果它是
std::list
,则将操作符应用于列表的所有值之间,否则弹出另一个值并进行加法,如果它们都是float)
到目前为止,我已经能够通过使用模板使其工作,例如。
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有这么多不同的库,我很难理解要找什么。如果我缺少一些更容易的东西,我不需要使用它,我没有想到在为这种任务放弃函数式语言时会发现这么多困难。
您需要boost::variant
,对于元素列表,需要boost::make_recursive_variant
(这样您就可以在类型中引用类型)。
虽然apply_visitor
允许您将函数应用于许多类型,但我发现像这样的东西更容易考虑开始(假设您的编译器支持c++ 11):
template<typename T, typename Func, typename Types...>
bool TryApplyFuncOn( boost::variant<Types...>& var, Func f ) {
struct HelperVisitor {
HelperVisitor( Func f_ ):func(f_) {}
Func func;
typedef bool return_type;
template<typename U>
return_type operator()( U& unused ) { return false; }
return_type operator()( T& t ) { f(t); return true; }
};
return boost::apply_visitor( HelperVisitor(f), var );
}
接受一个你想要应用函数的类型和一个变量,如果你想要应用的类型是变量中的类型,就应用它。如果找到匹配,则返回true。
一般情况下,您可以"一次完成"此操作。
你可以这样做:
// easy case:
typedef boost::variant<int,double> scalar;
scalar times_two(scalar const& left) {
scalar retval = left;
TryApplyFuncOn<int>( retval, []( int& value ){ value*=2; } );
TryApplyFuncOn<double>( retval, []( double& value ){ value*=2.; } );
return retval;
}
// tricky case:
scalar multiply(scalar const& left, scalar const& right) {
scalar retval = left;
TryApplyFuncOn<int>( retval, [&right]( int& left_value ){
TryApplyFuncOn<int>( right, [&left_value]( int& right_value ){
left_value *= right_value;
});
TryApplyFuncOn<double>( right, [&left_value]( double& right_value ){
left_value *= right_value;
});
});
TryApplyFuncOn<double>( retval, [&right]( double& left_value ){
TryApplyFuncOn<int>( right, [&left_value]( int& right_value ){
left_value *= right_value;
});
TryApplyFuncOn<double>( right, [&left_value]( double& right_value ){
left_value *= right_value;
});
});
return retval;
}
还没有进行类型提升(所以int*double不会变成double),但是没有什么基本的东西可以阻止它。
有意义吗?
相关文章:
- 在C++中对T*类型执行std::move的意外行为
- 仅在函数模板中为那些定义了函数的类型执行函数
- C++将一个指针分配给另一个指针时执行的类型检查
- C++如何乘以包含 std::variant 元素的向量的迭代器?正在执行迭代器类型的转换?
- 当前不会命中断点。没有调试器目标代码类型的可执行代码与此文件关联
- Eclipse 可执行架构类型
- 如何检查参数包是否具有执行顺序中的确切类型
- 如何对模板类型强制执行常量
- 执行特定函数取决于类型
- 根据运行时提供的类型执行模板函数
- 是否无法对长双数据类型执行openMP矢量化操作
- 是否可以使用循环对其所有类型执行类方法
- 如何对嵌套类型执行部分模板专用化
- 根据模板变量类型执行不同的方法
- 如果可变参数包为空,则对可变参数包类型执行替换
- 无法对代码合成 XML 类型执行操作
- 对模板中的每个其他类型执行static_assert
- 使用模板化的变量类型执行特定于上下文的操作
- 如何对模板中的字符串数据类型执行几组不同的指令
- 根据c++中的特定类型执行代码