C++ class iterator utility: definition and usage - c++

I have a class named A, and in this class I have an iterable container, which I do iterate through following some rules of access -- order, emptiness, and others.
To simplify the following example, lets consider I'm just iterating through the container, but this cannot be done using the built-in container's iterator.
class A {
public:
class iterator {
public:
// Constructor
iterator() {
}
// Destructor
~iterator() {
}
// Advances the iterator
void operator++() {
// Some accessing policy
}
};
private:
std::vector<int> a;
};
Everything works tremendously fine -- and looks very neat --, except that, when I do declare my iterator, I must use typename -- which I pretty much assume that is used in order to tell the compiler that what I have is a type, and not a class instanciation itself.
Questions:
why do I have to use typename when I do:
A a;
for (typename A::iterator it(...); it != ...; ++it) {
}
How are iterators commonly defined, since a vector iterator does not require the typename tag? Does it have to do with declaring the vector from the class definition, instead of from the vector itself?
std::vector<int> v;
for (std::vector<int>::iterator it(v.begin()); it != v.end(); ++it) {
}
Are the iterators defined inside the container class -- I guess it's named composition --, or, if not, how is it iterators are added to the namespace of a class, like in:
std::vector<int>::iterator it;

1 - why do I have to use typename when I do: [...]
You do not have to use typename. The typename disambiguator is required inside a template when you are using a dependent, qualified type name. This Q&A on StackOverflow clarifies things. This:
A a;
typename a::iterator it; // ERROR!
Is illegal C++. Provided that A is not the name of a template parameter, you should just do:
A::iterator it;
If you are inside a template and A is the name of a template parameter, such as in:
template<typename A>
struct X
{
void foo()
{
typename A::iterator it;
// ^^^^^^^^
// This is necessary here!
}
};
Then you have to use typename to tell the compiler that what follows the :: is the name of a type.
2 - How are iterators commonly defined, since a vector iterator does not require the typename tag?
Again, it is not true that "a vector iterator does not require the typename tag". If you have an explicit specialization of that vector, such as in:
std::vector<int>::iterator it; // "typename" not required
Then typename is not required, as it wasn't required in A::iterator it. If you are inside a template as in the following case, however, it will be required:
template<typename A>
struct X
{
void foo()
{
typename std::vector<A>::iterator it;
// ^^^^^^^^
// This is necessary here!
}
};
That's because std::vector<A>::iterator here is a qualified, dependent type name.
3 - Are the iterators defined inside the container class -- I guess it's named composition --, or, if not, how is it iterators are added to the namespace of a class, like in [..]
This could be done by defining a nested class, or simply done by using type aliases:
template<typename T>
struct X
{
typedef T* iterator;
iterator begin() { /* ... */ }
// ...
};
X<int>::iterator it; // OK: "typename" not required
template<typename T>
void foo(X<T>& x)
{
typename X<T>::iterator it = x.begin();
// ^^^^^^^^
// This is necessary here!
// ...
}

There are a lot of problems with your example code, so this may be the answer you are looking for (waves hand) :) Of course if your examples are not correct, then all bets are off.
I'm surprised that this would work at all. 'a' is a variable, 'A' is the class.
Also, when declaring a variable with a default constructor, you do not use ending parenthesis ().
A a;
A::iterator it;
for (A::iterator it; it != ...; ++it) {
}
Also, iterators are defined within the container class. Using typename should only be necessary when you are dealing with templates and only when the accessing something that could be interpreted as either a static member or function/nested class or typedef. This can be further explained by the answer here which was also given by Andy Prowl.
Good luck

Related

std::valarray and type of iterators

Since C++11 std::valarray has iterators, provided through the std::begin() and std::end() interfaces. But what is the type of those iterators (so that I can declare them properly)?
The following does not compile with a no template named 'iterator' in 'valarray<_Tp>' error:
template <typename T>
class A {
private:
std::valarray<T> ar;
std::valarray<T>::iterator iter;
public:
A() : ar{}, iter{std::begin(ar)} {}
};
decltype shows the type of the iterator to be that of a pointer to a ``valarray` element. Indeed, the following does compile and seems to work fine:
template <typename T>
class A {
private:
std::valarray<T> ar;
T* iter;
public:
A() : ar{}, iter{std::begin(ar)} {}
};
What am I missing? Isn't there a proper iterator type to use for the declare in the class?
But what is the type of those iterators
The type is unspecified.
(so that I can declare them properly)?
You can use decltype:
using It = decltype(std::begin(ar));
It iter;
Or, in cases where that's possible (not member variables), you should prefer type deduction:
auto iter = std::begin(ar);

How do I use the iterator type when inheriting publicly from an STL container class?

I am making a program in which I am inheriting publicly my Set class from a built-in STL container class set. I have to use the iterator type, while making some other specialized functions for my own Set class, as defined in the stl set class.
Now my question is: What would be the syntax to declare variables of iterator type inside my member functions? I have been trying:
template<typename T>
class Set : public set<T> {
public:
bool func()
{
iterator it,it2;
}
};
But the compiler is not recognizing iterator type. Kindly tell me the syntax to use the iterator type from the stl set class.
The compiler complains because it doesn't know that iterator is in fact a member of set<T>. set<T> is what's called a dependent type, because it depends on the type parameter T. In a nutshell, the compiler does not look inside dependent names when resolving types.
This FAQ entry is relevant to this question. Also, be sure to read through the answers to this Stack Overflow question. To fix it, use typename.
template<typename T>
class Set : public set<T> {
public:
bool func()
{
typename set<T>::iterator it;
typename set<T>::iterator it2;
}
};
But really, you should be using composition instead of inheritnace for this case, like this:
template<typename T>
class Set
{
public:
bool func()
{
typename set<T>::iterator it;
typename set<T>::iterator it2;
}
private:
std::set<T> set;
};
You should never ever ever ever ever inherit from an STL container class because the destructors of those classes are not virtual, and so every time you instantiate an instance of your derived class, you'll have a memory leak.
As In Silico suggested in one of his comments, give Set a member variable set instead of inheriting from it.

specializing iterator_traits

I'd like to specialize std::iterator_traits<> for iterators of a container class template that does not have the usual nested typedefs (like value_type, difference_type, etc.) and whose source I shouldn't modify. Basically I'd like to do something like this:
template <typename T> struct iterator_traits<typename Container<T>::iterator>
{
typedef T value_type;
// etc.
};
except that this doesn't work, as the compiler is unable to deduce T from Container<T>::iterator.
Is there any working way to achieve the same?
For example:
template <typename T>
class SomeContainerFromAThirdPartyLib
{
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
typedef T ValueType; // not value_type!
// no difference_type
...
};
iterator begin() { ... }
iterator end() { ... }
...
};
Now suppose I call std::count() using an instance of this class. As far as I know, in most STL implementations, count() returns iterator_traits<Iterator>::difference_type. The primary template of iterator_traits<I> simply does typedef typename I::difference_type difference_type. Same with the other nested types.
Now in our example this obviously won't work, as there's no Container::iterator::difference_type. I thought I could work around this without modifying the iterator class, by specializing iterator_traits for iterators of any Container<T>.
In the end, I just want to be able to use std algorithms like count, find, sort, etc., preferably without modifying any existing code. I thought that the whole point of iterator_traits is exactly that: being able to specify types (like value_type, diff_type etc.) for iterator types that do not support them built-in. Unfortunately I can't figure out how to specialize the traits class for all instances of Container<T>.
Yes. The compiler cannot deduce T from Container<T>::iterator because it is non-deducible context, which in other words means, given Container<T>::iterator, the value of T cannot uniquely and reliably be deduced (see this for detail explanation).
The only solution to this problem is that you've to fully specialize iterator_traits for each possible value of iterator which you intend to use in your program. There is no generic solution, as you're not allowed to edit the Container<T> class template.
Nawaz's answer is likely the right solution for most cases. However, if you're trying to do this for many instantiated SomeContainerFromAThirdPartyLib<T> classes and only a few functions (or an unknown number of instantiations but a fixed number of functions, as might happen if you're writing your own library), there's another way.
Assume we're given the following (unchangeable) code:
namespace ThirdPartyLib
{
template <typename T>
class SomeContainerFromAThirdPartyLib
{
public:
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
public:
typedef T ValueType; // not value_type!
// no difference_type
// obviously this is not how these would actually be implemented
int operator != (const iterator& rhs) { return 0; }
iterator& operator ++ () { return *this; }
T operator * () { return T(); }
};
// obviously this is not how these would actually be implemented
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
};
}
We define an adapter class template containing the necessary typedefs for iterator_traits and specialize it to avoid problems with pointers:
namespace MyLib
{
template <typename T>
class iterator_adapter : public T
{
public:
// replace the following with the appropriate types for the third party iterator
typedef typename T::ValueType value_type;
typedef std::ptrdiff_t difference_type;
typedef typename T::ValueType* pointer;
typedef typename T::ValueType& reference;
typedef std::input_iterator_tag iterator_category;
explicit iterator_adapter(T t) : T(t) {}
};
template <typename T>
class iterator_adapter<T*>
{
};
}
Then, for each function we want to be able to call with a SomeContainerFromAThirdPartyLib::iterator, we define an overload and use SFINAE:
template <typename iter>
typename MyLib::iterator_adapter<iter>::difference_type
count(iter begin, iter end, const typename iter::ValueType& val)
{
cout << "[in adapter version of count]";
return std::count(MyLib::iterator_adapter<iter>(begin), MyLib::iterator_adapter<iter>(end), val);
}
We can then use it as follows:
int main()
{
char a[] = "Hello, world";
cout << "a=" << a << endl;
cout << "count(a, a + sizeof(a), 'l')=" << count(a, a + sizeof(a), 'l') << endl;
ThirdPartyLib::SomeContainerFromAThirdPartyLib<int> container;
cout << "count(container.begin(), container.end(), 0)=";
cout << count(container.begin(), container.end(), 0) << std;
return 0;
}
You can find a runnable example with the required includes and usings at http://ideone.com/gJyGxU. The output:
a=Hello, world
count(a, a + sizeof(a), 'l')=3
count(container.begin(), container.end(), 0)=[in adapter version of count]0
Unfortunately, there are caveats:
As I said, an overload needs to be defined for each function you plan to support (find, sort, et cetera). This obviously won't work for functions in algorithm that haven't been defined yet.
If not optimized out, there may be small run-time performance penalties.
There are potential scoping issues.
In regards to that last one, the question is in which namespace to put the overload (and how to call the std version). Ideally, it would be in ThirdPartyLib so that it could be found by argument-dependant lookup, but I've assumed we can't change that. The next best option is in MyLib, but then the call has to be qualified or preceded by a using. In either case the end-user should either use using std::count; or be careful about which calls to qualify with std::, since if std::count is mistakenly used with SomeContainerFromAThirdPartyLib::iterator, it will obviously fail (the whole reason for this exercise).
An alternative that I do not suggest but present here for completeness would be to put it directly in the std namespace. This would cause undefined behavior; while it might work for you, there's nothing in the standard that guarantees it. If we were specializing count instead of overloading it, this would be legal.
In the specialization in question, T is in a nondeducible context but there is neither a third party library container code change nor any specialization in the std namespace required.
If the third party library does not provide any free begin and end functions in the respective namespace one can write own functions (into that namespace if desired to enable ADL) and wrap the iterator into an own wrapper class which in turn provides the necessary typedefs and operators.
First one needs the Iterator wrapper.
#include <cstddef>
namespace ThirdPartyStdAdaptor
{
template<class Iterator>
struct iterator_wrapper
{
Iterator m_it;
iterator_wrapper(Iterator it = Iterator())
: m_it(it) { }
// Typedefs, Operators etc.
// i.e.
using value_type = typename Iterator::ValueType;
using difference_type = std::ptrdiff_t;
difference_type operator- (iterator_wrapper const &rhs) const
{
return m_it - rhs.m_it;
}
};
}
Note: It would also be possible to make iterator_wrapper inherit from Iterator, or to make it more generic and have another helper to enable the wrapping of other iterators as well.
Now begin() and end():
namespace ThirdPartyLib
{
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator> begin(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator>(c.begin());
}
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > end(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > (c.end());
}
}
(It is also possible to have them in a different namespace than SomeContainer but loose ADL. IF there are begin and end functions present in the namespace for that container I'd tend to rename the adaptors to be something like wbegin and wend.)
The standard algorithms can be called using those functions now:
ThirdPartyLib::SomeContainer<SomeType> test;
std::ptrdiff_t d = std::distance(begin(test), end(test));
If begin() and end() are included into the library namespace, the container can even be used in more generic contexts.
template<class T>
std::ptrdiff_t generic_range_size(T const &x)
{
using std::begin;
using std::end;
return std::distance(begin(x), end(x));
}
Such code can be used with std::vector as well as ThirdPartyLib::SomeContainer, as long as ADL finds begin() and end() returning the wrapper iterator.
You can very well use the Container as template parameter to your iterator_traits. What matters to the rest of STL are the typedefs inside your traits class, such as value_type. Those should be set correctly:
template <class Container> struct iterator_traits
{
public:
typedef typename Container::value_type value_type;
// etc.
};
You would then use value_type where you would previously use T.
As for using the traits class, you of course parametrize it with the type of your external container:
iterator_traits<TheContainer> traits;
Naturally, this assumes TheContainer is conforms to the common STL containers' contract and has value_type defined correctly.

Generic iterator/pointer initialization

I have a C++ class Finder that stores a location in containers plus some additional data. Such containers have the type std::string but also char * or MyString. Say, the class looks like this (Iterator<TContainer>::Type is a trait / metafunction that returns the iterator type for a given container):
template <typename TContainer>
class Finder
{
public:
typedef typename Iterator<TContainer>::Type TIterator;
TIterator iterator;
// Initialization of iterator: How to do it generically?
// Finder {} // problem with pointers!
// Finder() : iterator(0) {} // problem with iterators!
};
The main problem now is how to initialize the iterator that can be a pointer or an iterator. If I only wanted to support my own containers then I could simply implement a constructor that takes nullptr_t following the nullptr idiom. However, since I want to support pointers, my own iterators and STL iterators, I'm a bit out of depth here.
The best thing that I can imagine is to write a getNil<>() function, e.g. the code below. However, now at least three questions arise:
Is this the best way to achieve my aim?
How to determine whether a type is a STL iterator? I would probably need some #ifs, and tailor code to each compiler/STL version to use.
Is it possible at all to get a nil iterator in the STL? Is the result of x-y in std::vector<int> x, y; int x = x-y; defined at all?
The code:
// Forward declaration.
template <typename T>
T getNil<T>();
template <typename TValue> TValue * getNil<TValue *>()
{ return NULL; }
template <typename TValue> TValue * const getNil<TValue * const>()
{ return NULL; }
template <> TValue * const getNil<MyIterator>()
{ return MyIterator(nullptr); } // nullptr from above idiom
template <> TStlIterator
boost::enable_if<
MagicallyDetermineIfIsStlIterator<TStlIterator>::value,
TStlIterator>
getNil<TStlIterator>()
{ return MyIterator(nullptr); } // nullptr from above idiom
Finder() : iterator() { }
Should do the trick. Not providing an argument for a member in the initialization list will call the default constructor on a type that has one, and will zero-initialize POD types including pointers (and it will fail if the type has no default constructor, but that seems unlikely given your scenario).

An std container inside a template method

Greetings.
I don't know very well how to explain myself, but I believe a piece of code will make you understand what I'm intenting to do :
template<class A, class B>
void myFunction(A<B>& list)
{
typename A<B>::iterator current = list.begin();
typename A<B>::iterator end = list.end();
while (current != end)
{
current++;
}
}
Where A is an STL container (vector, list...). It's like inception, but with templates : a template, inside a template, etc...
The thing is : what do you do when one of the params of your template is itself a template... and still want to support every types supported by this template.
This of course doesn't compile (it says 'A is not a template').
Does someone knows how to create such a template ?
You are looking for a template template parameter
template<template<class T, class All = std::allocator<T> > class A, class B>
void myFunction(A<B>& list)
{
typename A<B>::iterator current = list.begin();
typename A<B>::iterator end = list.end();
while (current != end)
{
current++;
}
}
However, in your particular case, I think you'd be better off by just passing the intantiated container, that is,
template<class C>
void myFunction(C& list)
{
...
}
use like this
vector<char> v;
myFunction(v);
Your original code would have to be called like this:
myFunction<std::vector, char> (v)
which is much more verbose and has no particular benefit
A and B will be concrete types (and not templates), thus A<B> makes no sense.
You can write your code this way:
template<class List>
void myFunction(List &list)
{
typename List::iterator current = list.begin();
typename List::iterator end = list.end();
while (current != end)
{
current++;
}
}
If you need to know what is the type of an element of that list, there is a typedef inside of the list for that:
typename List::value_type
Well, to solve this little example problem. It's quite simple. vector<int> is a class, so, you don't need to declare the A<B> in the prototype. You can just do this:
template<class A>
void myFunction(A& list)
{
typedef typename A::value_type B; //do this if you need to know the type of the elements.
typename A::iterator current = list.begin();
typename A::iterator end = list.end();
while (current != end)
{
current++;
}
}
But if you really need to, you can also declare the template argument as a template too:
template< template<class> class A, class B >
void myFunction(A<B>& list)
{
typename A<B>::iterator current = list.begin();
typename A<B>::iterator end = list.end();
while (current != end)
{
current++;
}
}
But the above is not really recommended and most class templates have a set of nested typedefs (like iterator and value_type in STL containers) so that you can access have all the information you need about the type without having to use these template template parameters. So, the first way is usually the preferred and more normal way to do it (it also is usually less trouble to make it work, i.e., the compiler tends to "dislike" template template parameters).
Additionally, you cannot use STL containers very easily with template template parameters because STL containers all have these "hidden" template arguments (e.g. "allocator", and "compare" for sorted containers). So, you would have to list all these as well, otherwise the compiler will not be able to make the match. And then, you won't have a very "generic" function because you will have to assume so much about the STL container that is past that it will only serve one or two types of containers. It is really better to use the first way.