I need a vector class that exposes a small subset of the std::vector API. Everything works except range-based for. Here my attempt at implementing a forward iterator, which however does not compile.
#include <vector>
#include <iostream>
template <class T>
class OwningVector : private std::vector<T*> {
using super = std::vector<T*>;
public:
OwningVector() = default;
~OwningVector()
{
for (T* e : *this)
delete e;
super::clear();
}
OwningVector(const OwningVector& other)
: super()
{
super::reserve(other.size());
for (T* e : other)
super::emplace_back(e->clone());
}
OwningVector& operator=(const OwningVector& other)
{
if (this == &other)
return *this;
OwningVector ret(other);
swap(*this, ret);
return *this;
}
void emplace_back(T* e) { super::emplace_back(e); }
size_t size() const { return super::size(); }
T* const& operator[](int i) const { return super::operator[](i); }
T* const& at(int i) const { return super::at(i); }
const T* back() const { return super::back(); }
// Here the questionable part of my code:
class Iterator : public std::vector<T*>::iterator {};
Iterator begin() const { return super::begin(); }
Iterator end() const { return super::end(); }
Iterator begin() { return super::begin(); }
Iterator end() { return super::end(); }
};
class A {
public:
A(int m) : m(m) {}
int m;
};
int main() {
OwningVector<A> v;
v.emplace_back(new A(1));
for (const A*const a: v)
std::cout << a->m << std::endl;
}
Compilation fails:
h.cpp: In instantiation of ‘OwningVector<T>::Iterator OwningVector<T>::begin() [with T = A]’:
h.cpp:56:27: required from here
h.cpp:43:43: error: could not convert ‘((OwningVector<A>*)this)->OwningVector<A>::<anonymous>.std::vector<A*, std::allocator<A*> >::begin()’ from ‘std::vector<A*, std::allocator<A*> >::iterator’ to ‘OwningVector<A>::Iterator’
43 | Iterator begin() { return super::begin(); }
| ~~~~~~~~~~~~^~
| |
| std::vector<A*, std::allocator<A*> >::iterator
h.cpp: In instantiation of ‘OwningVector<T>::Iterator OwningVector<T>::end() [with T = A]’:
h.cpp:56:27: required from here
h.cpp:44:39: error: could not convert ‘((OwningVector<A>*)this)->OwningVector<A>::<anonymous>.std::vector<A*, std::allocator<A*> >::end()’ from ‘std::vector<A*, std::allocator<A*> >::iterator’ to ‘OwningVector<A>::Iterator’
44 | Iterator end() { return super::end(); }
| ~~~~~~~~~~^~
| |
| std::vector<A*, std::allocator<A*> >::iterator
class Iterator : public std::vector<T*>::iterator {};
Why? This looks like a certain other language's way of doing that. It's also not guaranteed to work because vector<T*>::iterator
may actually be a pointer type, in which case you can't derive from it.
using Iterator = typename super::iterator;
using ConstIterator = typename super::const_iterator;
ConstIterator begin() const { return super::begin(); }
ConstIterator end() const { return super::end(); }
Iterator begin() { return super::begin(); }
Iterator end() { return super::end(); }
This works. The typename
is required up to C++17, can be dropped for C++20.