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


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.

上一篇C++的性能优化实践 map hash_map unodered_map性能
想对作者说点什么? 我来说一句