Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
Sorry if my English or my coding conventions are bad.
std::list is the STL list.
I am trying to make a library that will use std::list<>::iterator and std::list<>::reverse_iterator seamlessly to the user according to his choice.
First, I wouldn't like to implement all std::list<>::iterator methods. So I'll inherit them to my class:
template <class realIter> class directedListTypeIter : public realIter
The user will instantiate the directedListTypeIter with 2 possible templates:
directedListTypeIter<std::list<value>::iterator>
directedListTypeIter<std::list<value>::reverse_iterator>
It means that I should create the following assignment operators (or copy constructor):
directedListTypeIter& operator=(std::list<value>::reverse_iterator &constructorIter) {
  ((std::list<value>::reverse_iterator*)this)->operator=(constructorIter);
  return *this;
}
directedListTypeIter& operator=(std::list<value>::iterator &constructorIter){
  ((std::list<value>::reverse_iterator*)this)->operator=(constructorIter);
  return *this;
}
I need all this assignment operators for the following function implementation, and other similar implementations.
directedListTypeIter begin(std::list<value>& userList){ 
  directedListTypeIter<realIter> retVal;
  if (someCheck()){
    retVal = userList.begin();
  } else {
    retVal = userList.rbegin();
  }
  return retVal;
}
In different words- In order to implement the begin() function, and other similar functions I need, I should implement the assignment operator (or copy constructor).
 
Here is my questions:
1. All this depends on the existence and usage of the "value" struct. How can I remove this dependency?
 
2. If I had more possible inherited types, should I have been creating new assignment operator (or copy constructor) for each type? isn't the template programming meant not to copy that code? How can I make the same without copying the code to each operator?
 
3. What should I add so the following:
directedListTypeIter& operator=(realIter &constructorIter){
  ((realIter*)this)->operator=(constructorIter);
  return *this;
}
would compile- without adding something that lists all possible inherited values?
 
thanku.
 
p.s. This topic is about how to template the inheritance, and not about achieving the use of both iterator types in one interface. I mean- the "C++ Standard Library list" use case is just an example to better explain my issue.
Posted 11-Apr-13 5:11am
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

By doing that, you are going against the design principles of STL.
 
Maybe you can consider doing something like:
 
template <class F> void Iterate(const T &container, F func, bool forward)
{
  if (forward)
  {
     std::for_each(container.begin(), container.end(), func);
  }
  else
  {
    std::for_each(container.rbegin(), container.rend(), func);
  }
}
 
And when you have to iterate you can do something like:
 
Iterate(userList, someFunction, someCheck());
 
If you are using a recent compiler, you might even use lambda instead of function objects...
 
By using a simple function like this one, you can simplify calling code if you have to select direction a lot of time on a whole container.
 
Depending on what is similar and whjat varies, you might adapt the code so that common logic is inside the iterate function. Or it everything varies a lot, then you might simply uses for_each directly.
 
You might also look at boost range: http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/index.html[^]. I haven't uses them but it might be something that might help you or maybe give you some idea.
  Permalink  
v3
Comments
debil123 at 13-Apr-13 17:51pm
   
It is not the answer I was looking for. Did you read the "p.s." thing? It states that the example is just to clarify my question- how to template the inherited class.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

I don't think inheritance is the right tool for the job in this case. Would something like the following give you what you need with less issues.
 
< template typename T, template typename IteratorType = ForwardIteratorType >
struct MyContext
{
  public:
 
  typedef std::list< T > List;
  typedef std::list< T >::iterator Iterator;
};
 
< template typename T, ReverseIteratorType >
struct MyContext
{
  public:
 
  typedef std::list< T > List;
  typedef std::list< T >::reverse_iterator Iterator;
};
 
This is called partial template specialisation and is available in all recent C++ compilers, MSVC from 2010 should work before that more of a lottery back to VC6 none at all.
 
 MyContext< int, ReverseIteratorType >::Iterator rit;
 MyContext< int >::Iterator it;
 
Shold now give you reverse and standard iterators for a list of int without having to override or inherit anything.
The great thing with templates is you don't have to write any 'real' code until and unless you want to change or add functionality. All you need is the right incantation of template type declarations.
  Permalink  
Comments
debil123 at 11-Apr-13 12:03pm
   
Thanku for your answer. It may be a solution for the example issue.
But, it is not applicable in my case.
1. I can't use myContext instead of std::list.
2. when compiling templated code, I understand that the compiler duplicates the code. It means that both types of iterators can't share a single list. Because it defined twice. But, maybe we don't need that definition at all.
 

 
Anyway, it is not the answer I was looking for.
Did you read the "p.s." thing? It states that the example is just to clarify my question- how to template the inherited class.
Matthew Faithfull at 11-Apr-13 16:18pm
   
I'm still not sure I get what you're trying to do but if you must use inheritance for some reason what is to stop you doing this:
 
template< class Item > class directedListTypeIter : public typename std::list<item>::iterator
 
This keeps the directedListTypeIter generic but doesn't deal with which type of iterator, forward or back it is. Either way you don't need to reimplement the assignment operator unless you add data members.
debil123 at 13-Apr-13 17:49pm
   
this:
 
template< class Item > class directedListTypeIter : public typename std::list::iterator
 
does define which type of iterator it is. it is forward iterator.
 
but- as I said, the solution you posted in the beginning can solve my issue. but I am not interested in solving this particular issue of creating forward, or reverse iterator. I am interested in finding how to template inheritance.
I mean- why this:
directedListTypeIter& operator=(realIter &constructorIter){
((realIter*)this)->operator=(constructorIter);
return *this;
}
is ambiguity?
Matthew Faithfull at 13-Apr-13 19:47pm
   
The simple answer is because you don't need to write this function, it already exists for the base class and given that the derived class doesn't add any data, assignment operator is the same function as that of the base class. Technically this is to do with concepts like 'type coersion', 'promotion' and 'automatic type conversion' which you can research but put simply, don't write the function, it's not needed, no longer any ambiguity.
debil123 at 14-Apr-13 2:45am
   
it doesn't compile. assignment operator, although its trivial should be added to support the assignment needed by my begin() function.
Matthew Faithfull at 14-Apr-13 8:31am
   
In that case Id question whether your begin function is needed? Does it do something the base class function doesn't do or could it call the base class begin to do the assignment?
debil123 at 14-Apr-13 9:42am
   
It does do something that the base class can't do. The base class can't check the someCheck(). That's the whole point. All this needed for the begin(), end(), erase() and other functions which the iterator itself doesn't know how to do.
Matthew Faithfull at 14-Apr-13 10:25am
   
OK I see that. How about removing the assignment to a temporary from the implementation of begin and just returning the result of the base class begin directly.
 
directedListTypeIter begin(std::list& userList){
 
if (someCheck()){
 
return userList.begin();
 
} else {
 
return userList.rbegin();
 
}
 
}
 

 
It's kludgy but any error this gives might shed some light in itself. I still don't think you need to be doing this separation of which iterator type to use procedurally. I think it should be done by template specialization but you're welcome to try.
debil123 at 17-Apr-13 10:08am
   
In that way you have to implement copy constructor instead of the assignment operator for each iterator type.
I thought it is obvious from my original post.
Matthew Faithfull at 17-Apr-13 10:45am
   
Doesn't seem to bad, you should be implementing copy constructors anyway if the default/base class ones are either not callable or not correct.
debil123 at 17-Apr-13 10:49am
   
But both copy constructors are the same. why not to implement single generic one?
I mean- that's the original question is all about.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 5,130
1 DamithSL 4,237
2 Maciej Los 3,700
3 Kornfeld Eliyahu Peter 3,470
4 Sergey Alexandrovich Kryukov 2,846


Advertise | Privacy | Mobile
Web02 | 2.8.141216.1 | Last Updated 12 Apr 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100