Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

C++ bidirectional iterators for array of classes

Posted on 2013-11-13
1
408 Views
Last Modified: 2013-11-13
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
Comment
Question by:deleyd
1 Comment
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 39646298
>>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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question