I'm writing a class IteratorIterable
that wraps a container class (a class with begin()
and end()
methods returning some iterators) to make it possible to iterate over the iterators of the wrapped class. The idea is based on this post. My code looks like this (some methods left out for brevity):
template <class T>
class IteratorIterable
{
private:
T& container;
public:
typedef decltype(container.begin()) BackendIterator;
public:
class IteratorIterator
{
public:
IteratorIterator() : it() {}
IteratorIterator(BackendIterator it) : it(it) {}
IteratorIterator(const IteratorIterator& other) : it(other.it) {}
IteratorIterator& operator=(const IteratorIterator& other) { if (&other == this) return *this; it = other.it; return *this; }
BackendIterator operator*() const { return it; }
const BackendIterator* operator->() const { return ⁢ }
bool operator==(const IteratorIterator& other) { return it == other.it; }
bool operator !=(const IteratorIterator& other) { return it != other.it; }
IteratorIterator operator+(size_t n) { return IteratorIterator(it + n); }
IteratorIterator& operator++() { ++it; return *this; }
IteratorIterator operator++(int) { IteratorIterator cpy(*this); ++(*this); return cpy; }
private:
BackendIterator it;
};
public:
IteratorIterable(T& container) : container(container) {}
IteratorIterator begin() const { return IteratorIterator(container.begin()); }
IteratorIterator end() const { return IteratorIterator(container.end()); }
};
template <class T>
IteratorIterable<T> ItIt(T& container)
{
return IteratorIterable<T>(container);
}
The problem here is, the operator+()
method in IteratorIterator
is only valid for a random-access BackendIterator
, because otherwise the addition operator is not defined on the backend. I want my IteratorIterator to provide this method only if the backend supports it.
Consider this example code:
typedef list<int> Cont;
Cont vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
IteratorIterable<Cont> itb(vec);
IteratorIterable<Cont>::IteratorIterator beg = itb.begin();
IteratorIterable<Cont>::IteratorIterator it = beg;
it++;
//it = beg+1;
printf("%d\n", **it);
This compiles fine when using the it++
line, but - as expected - fails with the it = beg+1
line, because list<int>::iterator
is not random-access. I guess this is because if I don't actually instantiate IteratorIterator::operator+()
, the compiler doesn't care.
I know that templates are allowed to be valid only for some template arguments, but here the class is templated, not the method. Is it correct to instantiate a class template where one of the methods is invalid when that method is never used for this particular instantiation? GCC and Clang don't complain, but is it correct as per the C++ standard?