C++: Iterating through all of an object's members? C++遍历成员变量

转载 2016年05月31日 09:15:22


Suppose I have an object with many members:

class Example {
    AnotherClass member1;
    AnotherClass member2;
    YetAnotherClass member3;

Is there a short/concise way to do something like:

foreach(member m: myExample)

Instead of accessing each one individually?

I think I could put them in a vector and use a shared_ptr for the same effect, I was just wondering if say, Boost or some other popular library doesn't have something to do this automatically.

shareimprove this question
I really don't think that this is a good idea. If you need to iterate through something, then declare it as an iteratable container, or why would you not do this? – leftaroundabout Aug 22 '11 at 2:18
check out Boost serialization – Cheers and hth. - Alf Aug 22 '11 at 2:19
C++ doesn't have reflection. That means it's not possible. – Ryan Amos Aug 22 '11 at 2:22
Out of curiosity, how would this even be useful? Often when something is so fundamentally impossible it's because it wouldn't make sense in the first place. – Kerrek SB Aug 22 '11 at 2:30

6 Answers

up vote10down voteaccepted

C++ does not support class introspection, so you cannot iterate over all of the members in a class like that - not without having a (manually written) function that iterates over all members for you anyway.

You could, in principle, add a template member like so:

template<typename Functor>
void doAllMembers(Functor &f) {

That said, I would regard this as a broken design; you've gone and exposed all of your internal members publicly. What happens if you add one later? Or change the semantics of one? Make one a cached value that's sometimes out of date? etc. Moreover, what happens if you have members which don't all inherit from the same types?

Step back and reconsider your design.

shareimprove this answer

There are several solutions to this issue, contrary to what the naysayers blabber, but no built-in way.

C++ support a limited kind of introspection, at compile-time: you can check the template parameters.

Using either Boost.Tuple or Boost.Fusion (for its map), you can indeed achieve what you wish. In Boost.Fusion you even have BOOST_FUSION_ADAPT_STRUCT to transform a basic structure into a Fusion Sequence (and thus iterate it).

It requires quite a bit of template meta-programming though.

shareimprove this answer
Liked this solution. Posted the detailed code here: C++ iterate into nested struct field with boost fusion adapt_struct – minghua Sep 6 '12 at 7:04

C++ can do something like this, if you play by its rules and use template metaprogramming.

Instead of storing your stuff in a struct or class, store it in a tuple:

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

Then you can use template metaprogramming algorithms and so forth (see Boost.Fusion) to access members and poke at stuff. You can iterate, template-style, over the elements of the tuple.

shareimprove this answer

It is possible that what you're looking for here is the Visitor pattern. If you have an object as you describe, with a number of non-trivial member fields, and you find that you have a number of different functions that all traverse this data structure in the same way, the visitor pattern can be very helpful in reducing the amount of code duplication. It is not automatic, through, you have to write the functions that traverse all the member fields, but you only have to do that once, and you can use it many times over with different visitor classes that do different things.

The visitor pattern does involve writing quite a bit of code, you need an abstract base class for the visitors:

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 ...

Then you need accept functions in all the classes that are going to be visited:

void Example::accept( VisitorBase& visitor ) 

And finally you need to implement concrete visitor classes that do the actual work you're interested in, which generally amounts to gather information from the data structure, making changes to the data structure, or combinations of both. Google Visitor pattern and you'll find lots of help on this.

shareimprove this answer

This is my way to do what you want to achieve in C++11. It uses tuple and templates. It's not short and concise but if you wrap somecode in a header file is acceptable. There is my full compilable example:

#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

  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)


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);

int main() {

  Example example;

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

shareimprove this answer

This is not possible with C++, if you really Really REALLY need this then instead use C#. But I seriously doubt you do.

Having said that, about the only option you really have is to use .NET and use managed C++ which microsoft calls Managed C++/CLI. But the caveat, is your class must be a managed 'ref class', meaning a managed class. Eventually it all gets compiled down to MSIL, and intermediate language that is language agnostic. That's the only way you could then use .NET reflection on it at runtime to discover it's member functions and values. However even using .NET it's not as easy as you described how you would like to use it above. Another downside to reflection is that it's slow, so if you are using it heavily you have a bad design. Reflection is nice in that .NET uses it to help in serializing data types, which makes XML serialization very easy to use.



在实际的代码开发中,难免会遇到数据业务逻辑复杂的表,映射到实体类之后所有的字段都会变成对应类中的成员变量(前面有介绍插件自动生成实体类的插件介绍0.0) 在处理这些数量巨大的实体类的时候,取值赋值无...

C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法

c++ 中定义引用变量时必须同时初始化,所以只能是int a=10;int &b=a;的形式出现。所以一直觉得c++的类中是不能有引用成员变量的。 最近才发现类中是可以有引用成员变量的,只是它的初始...

C/C++ - 类中成员变量是引用

C/C++ - 类中成员变量是引用CC - 类中成员变量是引用 C引用 不能有默认构造函数必须提供构造函数 构造函数的形参必须为引用类型 初始化必须在成员初始化链表内完成 C++引用引用在定义时必须初...
  • lazyq7
  • lazyq7
  • 2015年09月03日 00:22
  • 3706


有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同。这些特殊的类型的成员变量包括: 1.引用 2.常量 3.静态 4.静态常量(整型) 5...


您举报文章:C++: Iterating through all of an object's members? C++遍历成员变量