Owen
Owen

Reputation: 4173

Unable to access contents of initialized struct from a vector

I have a struct:

typedef struct
{
    Qt::Key qKey;
    QString strFormType;
} KeyPair;

Now I initialize KeyPair instantiations so I could use it for my Automated Test App.

KeyPair gTestMenu[] =
{
    { Qt::Key_1 , "MyForm" },
    { Qt::Key_1 , "SubForm" },
    { Qt::Key_Escape, "DesktopForm" }
};

KeyPair gBrowseMenu[] =
{
    { Qt::Key_1 , "MyForm" },
    { Qt::Key_2 , "Dialog" },
    { Qt::Key_Escape, "DesktopForm" }
};

and like 100 more instantiations....

Currently, I call a function which uses these KeyPairs.

pressKeyPairs( gTestMenu );
pressKeyPairs( gBrowseMenu );
and more calls for the rest... 

I would like to put all these KeyPair instantiations in a vector so I wouldn't have to call pressKeyPairs() a hundred times... I'm a newbie in using vectors... so I tried:

std::vector<KeyPair, std::allocator<KeyPair> > vMasterList;
vMasterList.push_back( *gTestMenu );
vMasterList.push_back( *gBrowseMenu );

std::vector<KeyPair, std::allocator<KeyPair> >::iterator iKeys;
for(iKeys = vMasterList.begin(); iKeys != vMasterList.end(); ++iKeys)
{
    pressKeyPairs(*iKeys);
}

However, this code block isn't working... :( Can somebody tell me how to properly put these KeyPairs in a vector?

Upvotes: 0

Views: 288

Answers (2)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361412

You've to use insert to populate the vector with your different arrays. Here is how you should do it.

//initialized with one array
std::vector<KeyPair> vMasterList(gTestMenu, gTestMenu + 3);

//adding more items
vMasterList.insert( vMasterList.end(),  gBrowseMenu , gBrowseMenu  + 3); 

And then reimplement your pressKeyPair function, so that you can use std::for_each from <algorithm> header file as,

 //pressKeyPair will be called for each item in the list!
 std::for_each(vMasterList.begin(), vMasterList.end(), pressKeyPair);

Here is how you can write the pressKeyPair function:

  void pressKeyPair(KeyPair &keyPair) //takes just one item!
  {
       //press key pair!
  }

In my opinion, this is better design, as it doesn't need "manual" loop anymore at the calling site!

You can even call pressKeyPair for first 5 items in the list as,

 //pressKeyPair will be called for first 5 items in the list!
 std::for_each(vMasterList.begin(), vMasterList.begin() + 5, pressKeyPair);

One more example:

 //pressKeyPair will be called for 5 items after the first 5 items, in the list!
 std::for_each(vMasterList.begin()+5, vMasterList.begin() + 10, pressKeyPair);

EDIT:

If you want to use manual loop, then you've to use this:

std::vector<KeyPair>::iterator it;
for( it = vMasterList.begin(); it != vMasterList.end(); ++it)
{
    pressKeyPair(*it);
}

But I would say it's not as elegant as the approach described earlier. Remember, this assumes that the function pressKeyPair has this signature:

void pressKeyPair(KeyPair &keyPair); //it doesn't accept array!

Upvotes: 2

templatetypedef
templatetypedef

Reputation: 372804

I think that the problem is that the code

vMasterList.push_back( *gTestMenu );

Only adds a single element of gTestMenu to the vector, namely the first. The reason is that this code is equivalent to the following:

vMasterList.push_back( gTestMenu[0] );

From which I think it's a bit easier to see what's going wrong.

To fix this, you probably want to add all of the elements in gTestMenu to the master list. You can do this using the three-parameter vector::insert function:

vMasterList.insert(v.begin(),  // Insert at the beginning
                   gTestMenu,  // From the start of gTestMenu...
                   gTestMenu + kNumTests); // ... to the end of the list

Here, you'll need to specify how many tests are in gTestMenu as kNumTests. You can do the same for gBrowseMenu.

By the way, you don't need to specify the allocator type in the vector declaration if you just want to use the default std::allocator. You can just write

std::vector<KeyPair> vMasterList;

And you'll be totally fine.

Upvotes: 2

Related Questions