[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 463
  • Last Modified:

C++ bidirectional iterators for array of classes

I need an ordered list of classes (Items), and a bidirectional iterator that can go forwards or backwards through the ordered list, changing direction as I please.

Also if I'm at the end of the ordered list and seek the 'next' entry, I'd like to wrap around to the first entry. Similarly, if I'm at the beginning of the ordered list and seek the 'previous' entry, I'd like to wrap around to the last entry.

Currently I'm attempting to do this with a vector:
MyClass.h
class MyClass
{
private:
    std::vector<class Item*> myItems;
    std::vector<class Item*>::iterator currentItem;
public:
    Item* GetCurrentItem();
    Item* NextItem();
    Item* PrevItem();
    void  AddItem(Item *s);
};

Open in new window


MyClass.cpp
#include "StdAfx.h"
#include "MyClass.h"

Item* MyClass::GetCurrentItem()
{
    Item* s;
    s = *currentItem;
    return s;
}
void MyClass::AddItem(Item *s)
{
    myItems.push_back(s);
}

Item* MyClass::NextItem()
{
    Item* s;
    currentItem++;
    if (currentItem == myItems.end()) {currentItem = myItems.begin();}
    s = *currentItem;
    return s;
}

Item* MyClass::PrevItem()
{
    Item* s;
    currentItem--;
    if (currentItem == myItems.begin() - 1) {currentItem = myItems.end() - 1;}
    s = *currentItem;
    return s;
}

Open in new window


At this point I start thinking someone must have already invented what I'm trying to reinvent here.

Plus I have a problem when I add the tag std::bidirectional_iterator_tag so I can randomly travel both forwards and backwards as I please:
MyClass.h
class MyClass
{
private:
    std::vector<std::bidirectional_iterator_tag, class Item*> myItems;
    std::vector<std::bidirectional_iterator_tag, class Item*>::iterator currentItem;
public:
    Item* GetCurrentItem();
    Item* NextItem();
    Item* PrevItem();
    void       AddItem(Item *s);
};

Open in new window

I now get complaints about the code
void MyClass::AddItem(Item *s)
{
    myItems.push_back(s);
}

Open in new window

no instance of overloaded function "std::vector<_Ty, _Ax>::push_back [with _Ty=std::bidirectional_iterator_tag, _Ax=Item *]" matches the argument list    
This is getting complicated. Does C++ offer something besides vector which has the simple abilities I seek? Or, how can I modify the above so it works? (Do I even need to specify std::bidirectional_iterator_tag?)
0
deleyd
Asked:
deleyd
1 Solution
 
jkrCommented:
>>Do I even need to specify std::bidirectional_iterator_tag?

Err, no - you can just go with the regular iterators, both '++' and '--' are defined for them. This tag is used to describe the 'bidirectional' attribute when quering for an iterator's traits at run time via RTTI, e.g.

#include <iterator>
#include <vector>
#include <iostream>
#include <list>

using namespace std;

int main( )
{
   vector<int> vi;
   vector<char> vc;
   list<char> lc;
   iterator_traits<vector<int>:: iterator>::iterator_category cati;
   iterator_traits<vector<char>:: iterator>::iterator_category catc;
   iterator_traits<list<char>:: iterator>::iterator_category catlc;

   // These are both random-access iterators
   cout << "The type of iterator for vector<int> is "
       << "identified by the tag:\n " 
       << typeid ( cati ).name( ) << endl;
   cout << "The type of iterator for vector<char> is "
       << "identified by the tag:\n " 
       << typeid ( catc ).name( ) << endl;
   if ( typeid ( cati ) == typeid( catc ) )
      cout << "The iterators are the same." << endl << endl;
   else
      cout << "The iterators are not the same." << endl << endl;

   // But the list iterator is bidirectinal, not random access
   cout << "The type of iterator for list<char> is "
       << "identified by the tag:\n " 
       << typeid (catlc).name( ) << endl;

   // cout << ( typeid ( vi.begin( ) ) == typeid( vc.begin( ) ) ) << endl;
   if ( typeid ( vi.begin( ) ) == typeid( vc.begin( ) ) )
      cout << "The iterators are the same." << endl;
   else
      cout << "The iterators are not the same." << endl;
   // A random-access iterator is a bidirectional iterator.
   cout << ( void* ) dynamic_cast< iterator_traits<list<char>:: iterator>
          ::iterator_category* > ( &catc ) << endl;
}

Open in new window


Output:

The type of iterator for vector<int> is identified by the tag:
 struct std::random_access_iterator_tag
The type of iterator for vector<char> is identified by the tag:
 struct std::random_access_iterator_tag
The iterators are the same.

The type of iterator for list<char> is identified by the tag:
 struct std::bidirectional_iterator_tag
The iterators are not the same.
0012FF3B

Open in new window


(Example taken from MSDN)

>>Does C++ offer something besides vector which has the simple abilities I seek?

Both 'list' and 'vectorÄ iterators are already bidirectional. The codee you have in the first two snippets will already do what you asked for.

CAVEAT: Vector iterators will be invalidated once you add an item or remove one from the container. List iterators will stay valid, though.
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now