C++ C++;:遍历所有对象';s的成员?

C++ C++;:遍历所有对象';s的成员?,c++,boost,C++,Boost,假设我有一个包含许多成员的对象: class Example { AnotherClass member1; AnotherClass member2; YetAnotherClass member3; ... }; 是否有一种简短/简洁的方法来执行以下操作: foreach(member m: myExample) m.sharedMethod(); 而不是单独访问每一个 我想我可以把它们放在一个向量中,使用一个共享的ptr来达到同样的效果,我只是想

假设我有一个包含许多成员的对象:

class Example {
    AnotherClass member1;
    AnotherClass member2;
    YetAnotherClass member3;
    ...
};
是否有一种简短/简洁的方法来执行以下操作:

foreach(member m: myExample)
    m.sharedMethod();
而不是单独访问每一个


我想我可以把它们放在一个向量中,使用一个
共享的ptr
来达到同样的效果,我只是想知道,比如说,Boost或其他一些流行的库是否没有自动完成这项工作。

C++不支持类内省,所以你不能像这样迭代类中的所有成员,除非有(手动编写的)函数,它无论如何都会为您迭代所有成员

原则上,您可以添加一个模板成员,如下所示:

template<typename Functor>
void doAllMembers(Functor &f) {
  f(member1);
  f(member2);
  f(member3);
}
模板
void doAllMembers(函子&f){
f(成员1);
f(成员2);
f(成员3);
}
也就是说,我认为这是一个失败的设计;你已经公开了你所有的内部成员。如果你以后添加一个会怎么样?或者改变一个的语义?使一个成为缓存值,有时会过时?等等。此外,如果你有不都从相同类型继承的成员会怎么样


退一步,重新考虑你的设计。

< P>这是不可能的C++,如果你真的真的需要这个,那么用C。 但我真的很怀疑你

你说过,你唯一的选择是使用.NET和使用微软调用的托管C++ C++。但是警告,你的类必须是一个托管的“REF类”,这意味着一个托管类。最终,它都被编译成MSIL,中间语言是语言不可知的。这是唯一的方法。然后在运行时对其使用.NET反射来发现其成员函数和值。但是,即使使用.NET,也不像您在上面描述的那样容易。反射的另一个缺点是速度慢,因此如果您大量使用它,您的设计也很糟糕。


反射很好,因为.NET使用它来帮助序列化数据类型,这使得XML序列化非常容易使用。

C++可以做类似的事情,如果您遵循它的规则并使用模板元编程的话

不要将内容存储在结构或类中,而是将其存储在元组中:

typedef boost::tuple<AnotherClass, AnotherClass, YetAnotherClass> Example;
typedef boost::tuple示例;

然后您可以使用模板元编程算法等等(参见Boost.Fusion)访问成员和戳东西。您可以在元组的元素上以模板样式进行迭代。

您在这里寻找的可能是访问者模式。如果您有一个如您所描述的对象,有许多非平凡的成员字段,您会发现您有许多不同的函数,这些函数都是以同样的方式遍历此数据结构,访问者模式可以非常有助于减少代码重复量。它不是自动的,通过,您必须编写遍历所有成员字段的函数,但您只需这样做一次,并且您可以在执行不同任务的不同访问者类中多次使用它事情

访问者模式确实需要编写大量代码,您需要为访问者提供一个抽象基类:

class VisitorBase 
{
    virtual void enter(Example& e)=0;
    virtual void leave(Example& e)=0;
    virtual void enter(AnotherClass& e)=0;
    virtual void leave(AnotherClass& e)=0;
    etc ...
};
然后,您需要在所有要访问的类中接受函数:

void Example::accept( VisitorBase& visitor ) 
{
    visitor.enter(*this);
    member1.accept(visitor);
    member2.accept(visitor);
    member3.accept(visitor);
    visitor.leave(*this);
}

最后,您需要实现具体的访问者类来完成您感兴趣的实际工作,这通常相当于从数据结构收集信息,对数据结构进行更改,或两者的组合。Google访问者模式,您将在这方面找到很多帮助。

有几种解决方案可以解决此问题e、 与反对者的喋喋不休相反,但没有内在的方式

C++在编译时支持一种有限的内省:您可以检查模板参数

使用
Boost.Tuple
Boost.Fusion
(对于其映射),您确实可以实现您想要的。在Boost.Fusion中,您甚至可以使用Boost\u Fusion\u ADAPT\u STRUCT将基本结构转换为融合序列(从而迭代它)


不过,它需要相当多的模板元编程。

这是我的方法,可以实现您在C++11中想要实现的目标。它使用元组和模板。它并不简短,但如果您将一些代码封装在头文件中,则是可以接受的。 下面是我完整的可编译示例:

#include <iostream>
#include <string>
using namespace std;

#include <tuple>

//Our iteratation code

//first a iteration helper structure
template<int N = 0>
struct IterateP {
  template<class T>
  typename std::enable_if<(N < std::tuple_size<T>::value), void>::type
  iterate(T& t) {
    std::get<N>(t).sharedMethod(); //there is the method name
    IterateP<N+1>().iterate<T>(t);
  }

  template<class T>
  typename std::enable_if<!(N < std::tuple_size<T>::value), void>::type
    iterate(T&) {}
};

//wrapper of the helper structure for a more comfortable usage
template <typename T>
void iterate(T& t) { IterateP<>().iterate(t.members); } //look at the .members, is the name of the class tuple

//Helper notation macro. 
#define MEMBER(name, i) std::tuple_element<i,decltype(members)>::type &name = std::get<i>(members)

//YOUR CLASSES

struct AnotherClass {
  int value;
  void sharedMethod() { cout << value << endl; }
};

struct YetAnotherClass {
  string value;
  void sharedMethod() { cout << value << endl; }
};


//The class with iterable members
struct Example {
  std::tuple<AnotherClass, AnotherClass, YetAnotherClass> members; //members must be in a tuple

  //These are helper member definition to access the tuple elements as normal members (instance.member1)
  //If you don't you this you need to access the members with tuple classes
  MEMBER(member1, 0); //first param is the member name and the second is it's position in the tuple.
  MEMBER(member2, 1);
  MEMBER(member3, 2);
};

//USAGE
int main() {

  Example example;

  //setting members just as a normal class 
  example.member1.value = 1;
  example.member2.value = 2;
  example.member3.value = "hola";

  //magic
  iterate(example);
}
#包括
#包括
使用名称空间std;
#包括
//我们的迭代代码
//首先是一个迭代辅助结构
模板
结构迭代{
模板
typename std::enable_if::type
迭代(T&T){
std::get(t).sharedMethod();//有方法名
IterateP().iterate(t);
}
模板
typename std::enable_if::value),void>::type
迭代(T&){}
};
//辅助结构的包装,使用更舒适
模板
void iterate(T&T){iterate().iterate(T.members);}//看看.members,是类元组的名称
//辅助符号宏。
#定义成员(名称,i)std::tuple\u元素::type&name=std::get(成员)
//你的班级
构造另一个类{
int值;

void sharedMethod(){难道我真的不认为这是一个好主意。如果你需要迭代某个东西,然后将它声明为一个可迭代的容器,或者你为什么不这样做?检查Boost serializationC++没有反射。这意味着这是不可能的。出于好奇,这怎么会有用呢?通常当某个东西非常重要的时候可能是因为它一开始就没有意义。喜欢这个解决方案。在这里发布了详细代码: