在我的引擎中,我有一个简单的反射系统,在编译时填充了类信息(也就是说,围绕一组模板构建,这使我能够自动化生成元信息的过程)。
考虑以下示例:
class Type
{
//...
Map<PropertyHash, TypeProperty> _properties;
};
每种类型都有一个功能:
template <class T>
void InitializeType(TypeInitializer* typeInitializer);
负责类型初始化。TypeInitializer 几乎没有用于向类型添加字段和基本类型的方法。所以基本上,每一种新类型只需要专门化这个功能。稍后,当第一次查询类型时,TypeDatabase 会创建具体的 Type 对象并为其调用 InitializeType()(TypeInitializer 在构造过程中获取指向类型的指针)。例如:
struct CST
{
const float* fptr;
volatile Uint32 vuint;
void** vptr;
};
template <>
SvrInline void InitializeType<CST>(TypeInitializer* typeInitializer)
{
typeInitializer->AddProperty("fptr", &CST::fptr);
typeInitializer->AddProperty("vuint", &CST::vuint);
typeInitializer->AddProperty("vptr", &CST::vptr);
}
就是这样。所有魔法都在 TypeProperty 构造函数中完成,声明为:
template <class Object_type, class Property_type>
TypeProperty(const char* fieldName, Property_type (Object_type::* propertyPtr));
这使我可以知道该物业的确切类型。我测试它的大小、常数、易失性等,并将此信息保存在 TypeProperty 对象中。好的。
现在,我也需要成员功能相同的东西。“相同”意味着我可以像现在添加属性一样添加功能。
我的第一个想法是可变参数模板(我的引擎在构建时完全支持 C++11 特性):
template <typename Object_t, typename Return_t, typename... Args>
TypeMethod(const char* methodName, Return_t (Object_t::*)(Args&&... args)
{
//What now?
}
但是,我不知道应该如何从 args 中提取类型。我看到了一篇文章,其中介绍了一种使用函数重载的方法:
template <typename P, typename R, typename Arg1, typename... Args>
void Func(R (P::*)(Arg1 arg1, Args&&... args))
{
}
template <typename P, typename R, typename... Args>
void Func(R (P::*)(Args&&... args))
{
}
template <typename P, typename R>
void Func(R (P::*)())
{
}
函数被递归地“转发”(我知道这不是实际的递归),每次都少一个参数。但是,我看不出这如何适合我的情况。