我试图用C++在C++11实现中添加动态反射。
class Object {
public:
Object() = default;
~Object() = default;
};和从对象继承的两个类:
class Person : public Object {
public:
std::string name;
int age;
}
class Group : public Object {
public:
std::string groupName;
std::vector<Person> persons;
}我实现了RefectManager来记录所有类的元信息,并创建了一个具有类名的对象,例如:
Object *obj = RefectManager::CreateObject("Group");
MetaInfo *groupMeta = obj->GetMetaInfo();其中,"groupMeta“保存类组的元信息,它知道:
类组有一个字段列表,其中包含两个字段: *一个名为"groupName“的字段,其类型的名称是"std::string” *一个名为"Person“的字段,其类型的名称为”std::“,在向量中元素类型的名称为”Person“。
我可以通过这个人的名字获得这个人的元信息:
MetaInfo *personMeta = RefectManager::GetMetaInfo("Person");但是,是否有一种方法可以动态地枚举类组中具有反射元信息的"persons“字段,例如:
for (field in groupMeta's field list) {
if (field type's name is "std::string") {
get field's content as string
} else if (field type's name is "std::vector") {
// only the element type's name is known as "Person"
// **how to enumerate the field with vector type?**
// If we know the element's type through element type's name,
// we can do it as following:
// std::vector<GetType<"Person">::type> *p = (std::vector<GetType<"Person">::type> *)field;
// std::vector<GetType<"Person">::type>::iterator it = p->begin();
// for (; it != p->end(); ++it) {
// //now we can access the element in field
// }
}
}发布于 2016-10-21 18:02:18
vector<int>、vector<bool>和vector<Person>是不相关的类型。
您说的是“它们都是向量,内容不同”,但是在C++中,模板会生成类型。std::vector不是一种类型,而是一种类型的工厂。
我们还能在这里做点什么。我们可以讨论vector支持什么操作,以及我们关心什么。
假设我们只想读取我们的vector,实际上,我们只希望能够迭代!
从拥有any_view的想法开始,其中any_view是任何事物的视图(比如void*,但更聪明)。现在,vector<Foo>是一种range<any_view>。
这个“视图”概念将值从引用或指针中分割出来--指向值。您的Object类型适合于值,而不是值的视图。
您可以对Object*进行的大部分操作都是您希望在any_view上进行的操作;但是any_view并不拥有它正在查看的内容,不像Object。
接口(忽略细节)如下所示:
template<class It>
struct range_t{
It b, e;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
// etc
};
template<class X>
struct any_input_iterator{
// implement a boost-like type erasure wrapper around
// the concept of input iteration (read only single-pass iteration)
using self=any_forward_iterator;
friend bool operator==(self const&, self const&);
friend bool operator!=(self const&, self const&);
self& operator++();
self operator++(int);
X operator*()const;
using value_type = std::remove_reference_t<X>;
using reference = X;
// etc
};
template<class X>
using iterable_over = range_t< any_input_iterator<X> >;
struct any_view {
std::typeinfo const* get_typeid() const;
template<class T>
T* get_as() const;
iteratable_over<any_view> members() const;
};然后,我们编写生成描述any_view类型T的后端数据的特性类,并编写接受T&并生成any_view的转换构造函数。any_view保存一个指向实现详细信息的函数指针的手动vtable的指针,以及一个指向T&的void*,并将其方法分派给它(传入void*)。
这并不容易,但这是解决方案的路线图。一个完整的解决方案对于一个堆栈溢出的post来说有点大。
特别是,类型擦除类型擦除,其中包含super_any包含std::refs作为我们的any_view,我们输入擦除操作的"get成员“,然后我们使用一种基于ADL的自由函数或基于特征的方法来描述成员和如何得到他们,将工作。
完成所有这些之后,您的代码看起来可能如下所示:
for (auto field : data) {
if (*field.type_id() == typeid(std::string)) {
std::string s = *field.get_as<std::string>();
} else if (!field.members().empty()) {
for (auto&& e:field.members()) {
if (*e.second.type_id() == typeid(Person)) {
Person& p = *e.get_as<Person>();
}
}
}
}注意,在这个抽象中,vector只是一堆成员,它们是元素。让它与众不同也是可以做到的。
发布于 2016-10-23 17:25:53
多亏了Yakk,我用lambda函数完成了类型擦除。
在生成类成员的元信息时,我还将使用它生成lambda函数。
因此,在枚举容器时,让lambda函数来完成它,仅此而已。
再次谢谢你!
https://stackoverflow.com/questions/40180813
复制相似问题