简体   繁体   中英

C++ iterating a struct

Is it possible to iterate through a struct?

For example

struct team{
   int player1;
   int player2;
   int player3;
   int player4;
   ...
   int player99; 
   int size = 99;
}

then run a for loop to set or access foo 1-4?

i guess pseudocode would look something like

for(int i = 0; i < size; i++){
    player i = (i+1); 
 }

A more simplified explanation if that doesnt make sense is I Just want to be able to go through each variable without having to hard code player1 = 1; player2 =2.

One way is to put the players/elements into an array:

struct Team {
    static int const size = 99;
    int players[size];
};

And then:

for(int i = 0; i < size; ++i)
    int player = players[i];

I would propose to use container instead of many variables, for example you could use std::array or std::vector . This way it will be trivial to iterate, much easier to make a copy. But also it's better from design point of view: in case you decide to change the number of players it will be much easier to change the container rather than add/remove many fields

To answer your question as you've asked it, I believe that you can use the pre-compiler macro Pack (the exact phrase depends on your compiler) to guarantee the structure of the memory used to create an instance of your struct. And then you technically could increment a pointer to move through it... if you're mad. That would be a very poor way to do and not at all guaranteed to work on different compilers or even different days of the week. No what you want is a data structure to do the job for you; they come with a 100% cash-back guarantee!

The most basic structure to do this with is a fixed size array, eg:

struct team
{
    int players[99]; //an array
    int manager;
    int coach;
    string teamName;
    //etc etc
}

Then to access your players

team myTeam;
for(int i(0); i < 99; ++i)
{
    myTeam.players[i]; //do whatever
}

The limitation of an array is that you cannot change its size once it's created. So if you try

myTeam.players[99]; //accessing invalid memory - the array values are 0 - 98

More advanced

If you need a data structure that can change size after it's created, eg you might want to add a few more players to your team at some point in the future. Then you can use a dynamic data structure such as the std::vector or the std::deque or std::list

You can define pointer to member, like pointer to member function:

  typedef int team::*member_t;

You can have array of pointers to all your members:

  static member_t member[size];

With this approach defining member function to iterate over all members is easy:

  template <class F>
  void for_each(F f)
  {
     for (int i = 0; i < size; ++i)
       f(this->*member[i]);
  }

And with using of preprocessor macro - you can have in one place definition of all members, in other definition of pointer to members - so you will not make any mistake with changing their order. See full code:

struct team {
#define TEAM_MEMBERS(prefix,suffix) \
  prefix player1 suffix, \
  prefix player2 suffix, \
  prefix player3 suffix

  int TEAM_MEMBERS(,);
  static const int size = 3;
  typedef int team::*member_t;
  static member_t member[size];
  template <class F>
  void for_each(F f)
  {
     for (int i = 0; i < size; ++i)
       f(this->*member[i]);
  }
};
team::member_t team::member[team::size] = {
  TEAM_MEMBERS(&team::,)
};

And some test:

#include <iostream>

int main() {
  team t = { 0 };
  t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,0,0
  int n = 0;
  t.for_each([&n](int& m) { m = n++; });
  t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,1,2
  t.player2 = 7;
  t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,7,2
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM