C ++: Iterating through all members of an object?

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) m.sharedMethod(); 

Instead of accessing each one individually?

I think I can put them in a vector and use shared_ptr for the same effect, I'm just curious, tell me, Boost or some other popular library does not have something to do automatically for this.

+7
source share
6 answers

C ++ does not support class introspection, so you cannot iterate over all elements in a class like this - not without a function (written by hand) that iterates through all members anyway.

Basically you can add a template member, for example:

 template<typename Functor> void doAllMembers(Functor &f) { f(member1); f(member2); f(member3); } 

I would call it a broken design; you went through and exposed all your inner members publicly. What happens if you add it later? Or change the semantics of one? Make one cached value that is sometimes deprecated? etc. Also, what happens if you have members that do not all inherit from the same types?

Go back and review your design.

+11
source

There are several solutions to this problem, in spite of the fact that skeptics dump, but are not built in.

C ++ supports a limited type of introspection at compile time: you can check template parameters.

Using either Boost.Tuple or Boost.Fusion (for your card), you can really achieve what you want. In Boost.Fusion, you even have BOOST_FUSION_ADAPT_STRUCT to convert the base structure to a Fusion sequence (and therefore repeat it).

This requires quite a lot of meta-programming patterns.

+6
source

C ++ can do something similar if you play by your own rules and use template metaprogramming.

Instead of storing your things in a structure or class, store it in a tuple:

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

Then you can use template metaprogramming algorithms, etc. (see Boost.Fusion) to access members and poke things. You can iterate over a template style over tuple elements.

+3
source

It is possible that you are looking for the Visitor template here. If you have an object that you describe with several non-trivial member fields, and you find that you have several different functions that completely intersect this data structure in the same way, a visitor pattern can be very useful in reducing the amount of code duplication . This is not automatic, through, you should write functions that intersect all the fields of the participant, but you need to do this only once, and you can use it many times with different classes of visitors who do different things.

The visitor template includes enough code to write, you need an abstract base class for 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 to accept functions in all classes that will be visited:

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

And finally, you need to implement specific classes of visitors that perform the work you are interested in, which usually comes down to collecting information from the data structure, making changes to the data structure, or combinations thereof. Google Visitor and you will find a lot of help about this.

0
source

This is my way of doing what you want to achieve in C ++ 11 . It uses a tuple and patterns . It is not short and concise, but if you complete somecode in the header file, this is acceptable. There is my full compiled 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 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 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); } 
0
source

This is not possible with C ++, if you really RELIABLE need it, then use C #. But I seriously doubt that you are doing this.

Having said that, the only possible option that you really use is to use .NET and use managed C ++, which microsoft calls Managed C ++ / CLI. But a caveat, your class must be a managed “ref class”, which means a managed class. Ultimately, all this compiles to MSIL, and the intermediate language is agnostic. This is the only way that you could then use .NET reflection on it at run time to discover its member functions and values. However, even using .NET is not as simple as you described, as you would like to use it above. Another drawback is that it is slow, so if you use it heavily, your design is poor. The reflection is good that .NET uses it to help serialize data types, which makes XML serialization very easy to use.

-2
source

All Articles