I'm have a problem with my constructors.
I get the following error:
no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘std::multiset<std::__cxx11::basic_string<char> >::iterator {aka std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >}’
multiset.cpp:47:1: note: candidate: my_multiset::iterator::iterator()
my_multiset::iterator::iterator(void){}
multiset.h:17:10: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘const cpt323::my_multiset::iterator&’
multiset.h:17:10: note: candidate: constexpr my_multiset::iterator::iterator(cpt323::my_multiset::iterator&&)
multiset.h:17:10: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘my_multiset::iterator&&’
The code is working with the exception of this part, any suggestion on how to make the appropriate changes
class my_multiset : custom_datastructure
{
std::multiset<std::string> the_set;
std::multiset<std::string>::iterator head;
std::multiset<std::string>::iterator tail;
public:
class iterator : public custom_datastructure::iterator
{
std::multiset<std::string>::iterator current;
public:
iterator(void){};
iterator(std::multiset<std::string>::iterator a_set) : current(a_set)
{
}
};
multiset(void);
std::unique_ptr<custom_datastructure::iterator> begin(void)
{
head = the_set.begin();
return std::make_unique<my_multiset::iterator>(&head);
}
std::unique_ptr<custom_datastructure::iterator> end(void)
{
tail = the_set.end();
return std::make_unique<my_multiset::iterator>(&tail);
}
}
custom_datastructure is as below
struct datastructure
{
struct iterator
{
/** OPERATORS HERE **/
virtual std::unique_ptr<datastructure::iterator> operator++(void) = 0;
/** ETC **/
};
virtual std::unique_ptr<iterator> begin(void) = 0;
virtual std::unique_ptr<iterator> end(void) = 0;
}
Why is your code breaking?
The reason your code breaks is because unique_ptr can't be used as an iterator, so if you wrap your iterator in a unique_ptr when returning it from begin() and end(), then it isn't usable as an iterator anymore.
An iterator doesn't have to be a pointer; it just needs to act like one. In addition, an iterator shouldn't own data. A class owns data if the class is responsible for deleting that data, but an iterator shouldn't be responsible for deleting anything. It should just provide a way of accessing the data. This means that iterators can and should be passed around by value (instead of using std::unique_ptr).
How do we fix the design?
So here's the big question: are you trying to create an interface that returns some iterators, or are you trying to create an interface for things that act like iterators?
Creating an interface that returns some iterators
The most generic way to do this is through templates. The benefit of using templates is that it enables us to re-use this interface in a wide variety of situations, and we can #include the interface where we need it, without having any dependencies in the file defining the template.
template<class Iterator>
class Iterable {
public:
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
};
We can use this to define my_multiset as returning iterators to std::multiset:
class my_multiset
: public Iterable<typename std::multiset<std::string>::iterator>
{
std::multiset<std::string> the_set;
public:
using iterator = typename std::multiset<std::string>::iterator;
iterator begin() override {
return the_set.begin();
}
iterator end() override {
return the_set.end();
}
};
Creating a GenericIterator<Value> - a class that can be assigned any iterator
Because pointers-to-iterators act like pointers, and not the underlying iterator, instead of using a unique_ptr<BaseIterator>, we're going to want to create a wrapper class that handles everything for us, while still acting like a normal iterator.
You'll be able to use it just like any old iterator, except that it can be assigned or created with an iterator to anything that derefences to Value. That means that the same GenericIterator can bind to a list iterator, a vector iterator, or even a std::multiset iterator.
Example showing how it could be used:
#include <iostream>
#include <list>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3};
std::list<int> l{10, 20, 30};
GenericIterator<int&> begin, end;
begin = v.begin();
end = v.end();
for (; begin != end; ++begin)
{
std::cout << *begin << " ";
}
begin = l.begin();
end = l.end();
for (; begin != end; ++begin)
{
std::cout << *begin << " ";
}
}
What parts do we need to make GenericIterator?
GenericIterator is going to store a pointer to a virtual base class. We'll also need a derived class that implements the base for a specific Iter.
Base class:
The base class virtualizes the main functions of an iterator: Increment, Dereference, and equality. It also provides a clone() method so that it's possible to make copies of iterators. close() comes in handy when writing a GenericIterator class that wraps this functionality.
template <class Value>
class IteratorBase
{
public:
virtual Value operator*() const = 0;
virtual IteratorBase& operator++() = 0;
virtual bool operator!=(IteratorBase const&) const = 0;
virtual bool operator==(IteratorBase const&) const = 0;
// We need this function for making copies of the iterator
virtual IteratorBase* clone() const = 0;
virtual ~IteratorBase() = default;
};
Derived class:
This derived class can wrap basically any other iterator on the planet, and it overrides all the methods in IteratorBase to give a fully-functioning iterator.
template <class Iter, class Value>
class IteratorDerived : public IteratorBase<Value>
{
Iter it;
public:
IteratorDerived() = default;
IteratorDerived(Iter it) : it(it) {}
IteratorDerived(IteratorDerived const&) = default;
IteratorDerived(IteratorDerived&&) = default;
Value operator*() const override { return *it; }
IteratorBase<Value>& operator++() override
{
++it;
return *this;
}
bool operator!=(IteratorBase<Value> const& other) const override
{
auto* derived = dynamic_cast<IteratorDerived const*>(&other);
return derived == nullptr || it != derived->it;
}
bool operator==(IteratorBase<Value> const& other) const override
{
auto* derived = dynamic_cast<IteratorDerived const*>(&other);
return derived != nullptr && it == derived->it;
}
IteratorBase<Value>* clone() const override
{
return new IteratorDerived(*this);
}
};
Generic Wrapper:
This GenericWrapper encapsulates all the functionality of an iterator, and because of how we're writing it, you can automatically assign any iterator that deferences to a matching value type.
template <class Value>
class GenericIterator
{
std::unique_ptr<IteratorBase<Value>> iterator;
public:
GenericIterator() = default;
GenericIterator(GenericIterator const& it) : iterator(it.iterator->clone())
{
}
GenericIterator(GenericIterator&&) = default;
// Creates a GenericIterator from an IteratorBase
explicit GenericIterator(IteratorBase<Value> const& it)
: iterator(it.clone())
{
}
// Creates a GenericIterator from an IteratorDerived
template <class Iter>
explicit GenericIterator(IteratorDerived<Iter, Value> const& it)
: iterator(it.clone())
{
}
// Creates a GenericIterator by wrapping another Iter
template <class Iter>
GenericIterator(Iter it) : iterator(new IteratorDerived<Iter, Value>(it))
{
}
GenericIterator& operator=(GenericIterator const& it)
{
iterator = std::unique_ptr<IteratorBase<Value>>(it.iterator->clone());
return *this;
}
GenericIterator& operator=(GenericIterator&&) = default;
Value operator*() const { return *(*iterator); }
GenericIterator& operator++()
{
++(*iterator);
return *this;
}
bool operator==(GenericIterator const& other) const
{
return *iterator == *other.iterator;
}
bool operator!=(GenericIterator const& other) const
{
return *iterator != *other.iterator;
}
};
Optional: C++17 template deduction guide
We can write a template type deduction guide for GenericIterator that automatically fills in the correct template parameter, making it easy to wrap any other iterator.
template<class Iter>
GenericIterator(Iter) -> GenericIterator<decltype(*std::declval<Iter>())>;
Related
There are no similar concept of (Java) Collection in C++.
I can understand the reason, but I want to know whether there is any way to fake it elegantly.
Example
I have implemented many custom Collections.
They all have Iterator that works correctly, similar to std::vector, std::unordered_set, etc.
They are MyArray<T> , MyBinaryTree<T> and MySet<T>.
Here I will show a working code that show the location I want to fake it.
Let's say that I have 2 levels of program : library and user.
It does only one thing - User commands Library to eat all Orange*s in a bucket.
Library.h
class Library{
public: static void eatAll(const MyArray<Orange*>& bucket);
};
Library.cpp
#include "Orange.h"
void Library::eatAll(const MyArray<Orange*>& bucket){
for(auto orange:bucket){
orange->eaten();
}
}
User.h
MyArray<Orange*> bucket;
Library::eatAll(bucket);
It is OK.
Now, I want Library::eatAll to also support MyBinaryTree<Orange*>, I have some not-so-desirable approaches as below.
My poor solution
1. Java way
Make MyBinaryTree<T> and MyArray<Orange*> (and their iterator) inherit from a new class Collection<T> (and CollectionIterator<T>).
change signature to Library::eatAll(const Collection<T>&)
Disadvantage : performance penalty from "virtual" of some functions in Collection<T>.
2. Template v1
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
orange->eaten();
}
}
make eatAll a template function
Disadvantage : The implementation of the eatAll must be in header.
I have to #include orange.h in Library.h.
Sometimes, I really want to just forward declaration.
3. Template v2
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
eatAnOrange(orange)
}
}
private: void eatAnOrange(Orange* orange){
//below implementation is inside Library.cpp
orange->eaten();
}
create a middle-man function eatAnOrange
Disadvantage :
Code is less readable, not concise, cause a little maintainability problem.
If there are a lot of other functions e.g. squeezeAll(), I probably have to create a lot of middle-man functions, e.g. squeezeAnOrange().
4. Operator=()
Create converter among the 3 collection classes via implicit constructor.
Disadvantage : Suffer performance from creating a new instance of collection.
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
I believe my solutions are inelegant.
Are there any solutions that don't suffer the mentioned disadvantage?
Edit:
Both of current answers are elegant than my approaches (thank!), but still has disadvantage :-
- Oliv's requires #include "orange.h" in User.h.
- Richard Hodges's has virtual function calling.
In C++, collections are traversed using the iterator design pattern. The entire STL is designed around this concept. It may fit your needs:
You could define eatAll as a function that accept two iterators:
template<class Iterator,class Sentinel>
void eatAll(Iterator it, Sentinel s){
for (;it!=s;++it)
it->eaten();
}
Or the range like algorithm interface:
template<class Range>
void eatAll(Range& r){
for (auto& v:r)
v.eaten();
}
You will have to define you binary tree as a range (it must implement begin() and end()). Hopefully trees are kind of graph that can be linearised. All the smart work will then go in the iterator implementation!
If you want it truly polymorphic, then we have to deal with 2 things:
the actual type of the container
The fact that the result of dereferencing a map is a pair containing key and value references.
My view is that the answer to this is not to derive from containers, which is limiting, but to create a polymorphic "value iterator", which models all iterators and extracts their values correctly.
Then we can write code like this:
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}
To get this:
vector:
Orange
Orange
map:
Orange
Orange
Orange
Here's a minimal, complete implementation:
#include <typeinfo>
#include <memory>
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
// define an orange
struct Orange {
};
// a meta-function to get the type of the value of some iterated value_type
template<class ValueType> struct type_of_value
{
using type = ValueType;
};
// specialise it for maps and unordered maps
template<class K, class V> struct type_of_value<std::pair<K, V>>
{
using type = V;
};
template<class ValueType> using type_of_value_t = typename type_of_value<ValueType>::type;
// function to extract a value from an instance of a value_type
template<class ValueType> struct value_extractor
{
template<class V>
auto& operator()(V&& v) const {
return v;
}
};
// specialised for maps
template<class K, class V> struct value_extractor<std::pair<K, V>>
{
template<class Arg>
auto& operator()(Arg&& v) const {
return std::get<1>(v);
}
};
template<class Iter>
auto extract_value(Iter const& iter) -> auto&
{
using value_type = typename std::iterator_traits<Iter>::value_type;
auto e = value_extractor<value_type> {};
return e(*iter);
}
// a polymorphic (forward only at the moment) iterator
// which delivers the value (in the case of maps) or the element (every other container)
template<class ValueType>
struct PolymorphicValueIterator {
using value_type = type_of_value_t<ValueType>;
private:
struct iterator_details {
std::type_info const &type;
void *address;
};
struct concept {
virtual std::unique_ptr<concept> clone() const = 0;
virtual value_type& invoke_deref() const = 0;
virtual void invoke_next(std::size_t distance = 1) = 0;
virtual iterator_details get_details() = 0;
virtual bool is_equal(const iterator_details &other) const = 0;
virtual ~concept() = default;
};
template<class Iter>
struct model final : concept {
model(Iter iter)
: iter_(iter)
{}
std::unique_ptr<concept> clone() const override
{
return std::make_unique<model>(iter_);
}
virtual value_type& invoke_deref() const override {
return extract_value(iter_);
}
void invoke_next(std::size_t distance = 1) override
{
iter_ = std::next(iter_, distance);
}
iterator_details get_details() override {
return {
typeid(Iter),
std::addressof(iter_)
};
}
bool is_equal(const iterator_details &other) const override {
if (typeid(Iter) != other.type) {
return false;
}
auto pother = reinterpret_cast<Iter const*>(other.address);
Iter const& iother = *pother;
return iter_ == iother;
}
Iter iter_;
};
std::unique_ptr<concept> concept_ptr_;
public:
bool operator==(PolymorphicValueIterator const &r) const {
return concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
bool operator!=(PolymorphicValueIterator const &r) const {
return not concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
PolymorphicValueIterator &operator++() {
concept_ptr_->invoke_next(1);
return *this;
}
value_type& operator*() const {
return concept_ptr_->invoke_deref();
}
template<class Iter>
PolymorphicValueIterator(Iter iter)
{
concept_ptr_ = std::make_unique<model<Iter>>(iter);
}
PolymorphicValueIterator(PolymorphicValueIterator const& r)
: concept_ptr_(r.concept_ptr_->clone())
{}
PolymorphicValueIterator& operator=(PolymorphicValueIterator const& r)
{
concept_ptr_ = r.concept_ptr_->clone();
return *this;
}
};
template<class Iter>
auto makePolymorphicValueIterator(Iter iter)
{
using iter_value_type = typename std::iterator_traits<Iter>::value_type;
using value_type = type_of_value_t<iter_value_type>;
return PolymorphicValueIterator<value_type>(iter);
}
// a test
void do_orange_things(PolymorphicValueIterator<Orange> first, PolymorphicValueIterator<Orange> last)
{
while(first != last) {
std::cout << "Orange\n";
++first;
}
}
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}
Apologies that this is pretty long, but I couldn't figure out how to make it shorter and still show the important features of my problem.
I'm asking this even though I have come up with an idea of how to do what I want, but it requires implementing an iterator in a way that doesn't match the standard iterator pattern. I would like to ask for any suggestions on how this could be done in a more standard or better way.
I have an abstract base class. Any subclass of it will have some collections of objects. There is some common code that I would like to put in the base class that needs to iterate over all of the objects in the collections. The objects in the collections will all descend from another abstract base class, but will be subclass objects. There may be multiple collections of objects from multible subclasses, and the collections may be different collection types. What I'd really like to do is something like this: (Note: this code will not compile.)
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool operator!=(iterator& other) = 0;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
int processCollections()
{
iterator it;
int sum = 0;
for(it = begin(); it != end(); ++it)
{
sum += (*it).someInterface(7);
}
return sum;
}
};
And then I want some subclasses of CollectionObjectBase and MyObjectBase like this:
class CollectionObject1 : public CollectionObjectBase { ... }
class CollectionObject2 : public CollectionObjectBase { ... }
class CollectionObject3 : public CollectionObjectBase { ... }
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::vector< CollectionObject2>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
class MyObjectB : public MyObjectBase
{
public:
std::vector<CollectionObject1> someThings;
std::set< CollectionObject3> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::vector<CollectionObject1>::iterator it1;
std::set< CollectionObject3>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
There are some big problems with the above code. First, MyObjectBase::begin() and MyObjectBase::end() can't return MyObjectBase::iterator because MyObjectBase::iterator is an abstract class, and you wouldn't want to anyway because you actually want a subclass of MyObjectBase::iterator that knows how to iterate over the collections in the subclass of MyObjectBase. You need to return a reference to MyObjectBase::iterator.
The second problem comes with MyObjectA::iterator::operator!=(). You'd like to do something like this:
virtual bool operator!=(iterator& other)
{
return it1 != other.it1 || it2 != other.it2;
}
But to be an overload of MyObjectBase::iterator::operator!=() it has to take a parameter of type MyObjectBase::iterator& and that doesn't have members it1 and it2. My best idea I've thought of to resolve this is to replace operator!=() with a function atEnd(), since the only thing it is being used for in this code is to detect if the iterator is at the end, but it makes it really non-standard.
Finally, MyObjectA::begin() and MyObjectA::end() cannot return a temporary. Remember, we have to return a reference to a MyObjectBase::iterator that points to a MyObjectA::iterator, not copy construct a MyObjectBase::iterator. My best idea I've thought of to resolve this is to allocate the iterator with new, and when I do that I need to return a pointer, not a reference so that the caller can delete it. So here's my final code. It works and performs the function of an iterator, but it is non-standard. Can anyone think of a way to do this with an iterator that fits the standard pattern?
#include <map>
#include <vector>
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool atEnd() = 0;
};
virtual iterator* begin() = 0;
int processCollections()
{
iterator* it;
int sum = 0;
for (it = begin(); !it->atEnd(); ++it)
{
sum += (**it).someInterface(7);
}
delete it;
return sum;
}
};
class CollectionObject1 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 1;
}
};
class CollectionObject2 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 2;
}
};
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::map<int, CollectionObject1>::iterator it1End;
std::vector< CollectionObject2>::iterator it2;
std::vector< CollectionObject2>::iterator it2End;
iterator(std::map<int, CollectionObject1>::iterator it1Init, std::map<int, CollectionObject1>::iterator it1EndInit,
std::vector< CollectionObject2>::iterator it2Init, std::vector< CollectionObject2>::iterator it2EndInit) :
it1(it1Init),
it1End(it1EndInit),
it2(it2Init),
it2End(it2EndInit)
{
// Initialization handled by initialization list.
}
virtual CollectionObjectBase& operator*()
{
if (it1 != it1End)
{
return (*it1).second;
}
else
{
return *it2;
}
}
virtual iterator& operator++()
{
if (it1 != it1End)
{
++it1;
}
else
{
++it2;
}
return *this;
}
virtual bool atEnd()
{
return it1 == it1End && it2 == it2End;
}
};
virtual MyObjectBase::iterator* begin()
{
return new iterator(someThings.begin(), someThings.end(), otherThings.begin(), otherThings.end());
}
};
There's an issue with useless' answer. Consider these subclasses of Impl and Base:
class MyImpl : public Base::Iterator::Impl {
public:
MyImpl(std::vector<CollectionObjectSub>::iterator itInit) : it(itInit) {}
CollectionObjectBase& operator*() { return *it; }
void operator++() { ++it; }
// bool operator==(Base::Iterator::Impl const &other) const { it == other.it; }
bool operator==(MyImpl const &other) const { it == other.it; }
private:
std::vector<CollectionObjectSub>::iterator it;
};
class Sub : public Base {
public:
Iterator& begin() { return Iterator(new MyImpl(collection.begin())); }
private:
std::vector<CollectionObjectSub> collection;
};
Sub contains a vector and MyImpl contains a vector iterator. I'd like to instantiate a Base::Iterator with impl_ pointing at a MyImpl. If MyImpl::operator== takes a MyImpl& then it isn't overloading Base::Iterator::Impl::operator==, but if it takes a Base::Iterator::Impl& then I can't access the vector iterator even if it actually is a MyImpl.
It seems like I need to do a dynamic cast to get a MyImpl, which requires RTTI. I've heard to avoid using RTTI if possible. Is there another way?
So, you want to return an iterator by value, but have its dynamic type vary depending on the override of begin/end you called? No problem - just add another layer of indirection.
class Base {
public:
class Iterator {
public:
struct Impl {
virtual ~Impl() {}
virtual CollectionObjectBase& operator*() = 0;
virtual void operator++() = 0;
virtual bool operator==(Iterator::Impl const &other) const = 0;
};
Iterator() {}
explicit Iterator(std::unique_ptr<Impl> &&i) : impl_(std::move(i)) {}
Iterator(Iterator &&other) = default;
CollectionObjectBase& operator*() { return **impl_; }
Iterator& operator++() { ++*impl_; return *this; }
bool operator==(Iterator const &other) const {
return (!impl_ && !other.impl_) || (*impl_ == *other.impl_);
}
private:
std::unique_ptr<Impl> impl_;
};
// ...
This uses the pointer-to-impl (pimpl) idiom to give each concrete subclass of Base its own concrete subclass of Base::Iterator::Impl, but still let you pass Base::Iterator objects around by value using move semantics to transfer ownership of the dynamic object.
NB. I made two default-constructed (nullptr) iterators compare equal so you don't need to create a real instance for end.
I have a custom container which I want to use in a ranged-based for loop. The container is somewhat based on a vector, like this:
template<typename T>
class IDMap
{
private:
struct Item {
uint16_t mVersion;
T mItem;
template <typename... Arguments>
Item(uint16_t version, Arguments&&... args) : mVersion(version), mItem(args...)
{
}
};
public:
typedef uint32_t ItemID;
template <typename... Arguments>
ItemID AddItem(Arguments&&... args);
void MarkAsFree(const ItemID id);
T& GetItem(const ItemID id);
T* TryGetItem(const ItemID id);
void Clear();
private:
std::vector<Item> mItems;
std::vector<uint16_t> mFreeIndices;
};
I want to iterate the mItems vector, but only return the mItem member rather than the entire Item struct. Is there any easy/elegant way to do this?
You have to provide a begin and end function, both returning a corresponding iterator, which itself implements operators ++, != and *. The begin and end functions can be free-standing or as members.
Start with implementing an iterator which has the behavior you want. You can implement it as a wrapper around a std::vector::iterator to save most of the "core" work.
The following is untested code
Basically, inside class IDMap, add:
class ItemIterator {
// based on vector iterator
std::vector<Item>::iterator i;
public:
ItemIterator(std::vector<Item>::iterator i) : i(i) {}
// incrementing
ItemIterator & operator ++() { ++i; return *this; }
ItemIterator operator ++(int) { const_iterator old(*this); ++(*this); return old; }
// comparison
bool operator!=(const ItemIterator &o) const { return i != o.i; }
// dereferencing
const T & operator*() const { return i->mItem; }
};
using iterator = ItemIterator;
using value_type = T;
ItemIterator begin() const { return ItemIterator(mItems.begin()); }
ItemIterator end() const { return ItemIterator(mItems.end() ); }
If you ever want to support multiple kinds of "special iteration" over your IDMap, like for example also over the indices, or over the "whole" Items, you should wrap everything above in another adaptor. This adaptor can then be accessed with a member method, like .items().
Brief example:
class IDMap {
// (your code)
public:
struct ItemsAdaptor {
// (insert above iterator definition + usings)
ItemsAdaptor(std::vector<Item>::iterator b,
std::vector<Item>::iterator e)
: b{b}, e{e}
{}
ItemIterator begin() const { return b; }
ItemIterator end() const { return e; }
private:
ItemIterator b, e;
};
ItemsAdaptor items() const {
return ItemsAdaptor(mItems.begin(), mItems.end());
}
};
Then, you can write:
IDMap<int> map = ...;
for (int i : map.items()) {
...
}
If you want the range-based for to work for your container, you have to provide begin and end functions that return forward iterators.
typedef std::vector<Item>::iterator iterator;
typedef std::vector<Item>::const_iterator const_iterator;
iterator begin()
{
return mItems.begin();
}
const_iterator begin() const;
{
return mItems.begin();
}
//also add end functions, and viola.
This will return the whole item struct. If you have to only return mItem, you'll have to write your own iterator adaptor and use it instead of vector's.
The premise
Say I have a container class Box which provides inner classes const_iterator and iterator. Because I want an iterator to be castable to a const_iterator, the latter inherits from the former:
class Box {
// ...
public:
class const_iterator : public std::iterator<std::random_access_iterator_tag, const int> { /* ... */ };
class iterator : public const_iterator { /* ... */ };
// ...
};
The problem
Now I want to test these classes using Google Test. Let's assert that the begin() and end() don't return the same thing:
const Box a;
EXPECT_NE(a.begin(), a.end());
Say hello to a compile error:
clang: no member named 'begin' in 'Box::const_iterator'
g++: ‘const class Box::const_iterator’ has no member named ‘begin’
The cause
Some research led me to this template in the Google Test source code (follow the link for expanded documentation):
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,
typename C::iterator* /* it */ = NULL,
typename C::const_iterator* /* const_it */ = NULL) {
return 0;
}
The result of this template magic is that if arguments to EXPECT_* have iterator and const_iterator member classes, then the type is assumed to be a container class. Knowing this, Google Test can print pretty human-readable reports when expectations fail, which is nice.
However, there's this little detail:
// Note that we look for both C::iterator and C::const_iterator. The
// reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator'). If we look for C::iterator
// only, for example, we would mistakenly think that a class named
// iterator is an STL container.
so if I understand things right, this means that
Box::const_iterator has itself as a member class named const_iterator, and std::iterator as a memberclass named iterator.
Box::iterator has itself as a member class named iterator and Box::const_iterator as a member class named const_iterator.
Therefore both my iterator classes look like container classes to Google Test!
The question
How do I design my iterator classes to make them not look like containers?
Things I've tried:
Declaring the std::iterator superclass of const_iterator as private. This solves the problem for const_iterator by hiding the iterator member class, but it still doesn't let me pass a.begin() as a parameter to EXPECT_NE unless a is const. Seems like Google Test uses iterator begin() rather than const_iterator begin() const for some reason.
Removing the std::iterator superclass altogether. Is this a bad idea? I suppose I'll have to declare my std::iterator_traits manually, is there anything else I'll lose by not extending std::iterator?
Declaring the Box::const_iterator superclass of Box::iterator as private. This may or may not be an option since I'd have to redeclare methods I'd rather want to reuse (such as operator++).
Is there anything else I've overlooked?
The example
#include<iterator>
#include <memory> //unique_ptr<T>
#include <gtest/gtest.h>
class ThreeInts {
std::unique_ptr<int[]> v;
public:
ThreeInts() : v(new int[3]) { v[0] = 0; v[1] = 1; v[2] = 2; };
ThreeInts(int val) : ThreeInts() { v[0] = val; v[1] = val; v[2] = val; };
bool operator==(const ThreeInts& other) const {
return v[0] == other.v[0] && v[1] == other.v[1] && v[2] == other.v[2];
}
class const_iterator : public std::iterator<std::random_access_iterator_tag, const int> {
protected:
int* p;
public:
explicit const_iterator(int* p) : p(p) {}
const_iterator& operator++() { ++p; return *this; }
bool operator==(const const_iterator& rhs) const { return p == rhs.p; }
bool operator!=(const const_iterator& rhs) const { return p != rhs.p; }
int operator*() const { return *p; }
};
class iterator : public const_iterator {
public:
explicit iterator(int* p) : const_iterator(p) {}
int& operator*() const { return *p; }
};
iterator begin() { return iterator(v.get()); }
iterator end() { return iterator(v.get()+3); }
const_iterator begin() const { return const_iterator(v.get()); }
const_iterator end() const { return const_iterator(v.get()+3); }
};
TEST(ThreeInts, ThisTestCompilesAndPrettyFailureMessagesAreShown) {
const ThreeInts a(1), b(2);
ThreeInts c(1), d(2);
EXPECT_EQ(a, b);
EXPECT_EQ(a, c);
EXPECT_EQ(c, d);
}
TEST(ThreeInts, ThisTestCompilesIfTheStdIteratorParentIsPrivate) {
const ThreeInts a;
EXPECT_NE(a.begin(), a.end());
}
TEST(ThreeInts, ThisTestAlsoCompilesIfTheStdIteratorParentIsPrivateButItIsAHassle) {
ThreeInts a;
ThreeInts::const_iterator beg = a.begin();
ThreeInts::const_iterator end = a.end();
//EXPECT_NE(beg, end); // Compile error unless the std::iterator superclass is private
}
TEST(ThreeInts, ThisTestDoesNotCompileEvenIfTheStdIteratorParentIsPrivate) {
ThreeInts a;
//EXPECT_NE(a.begin(), a.end());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
ThreeInts::iterator should not inherit from ThreeInts::const_iterator, instead they should be implemented separately.
class ThreeInts::iterator : public std::iterator< std::random_access_iterator_tag, int> { ... }
class ThreeInts::const_iterator : public std::iterator< std::random_access_iterator_tag, const int> { ... }
The problem seems to be that otherwise ThreeInts::const_iterator both has members named const_iterator and iterator (aka the constructors). Also making the iterator inherit from const_iterator is not const-correct as the const_iterator should only hold a pointer/similar to const data. STL containers also keep the two iterators separate.
In that code, it would probably be sufficient to instead of defining iterator classes, simply define
using iterator = int*;
using const_iterator = const int*;
I have a class that includes a std::list and wish to provide public begin() and end() for const_iterator and private begin() and end() for just plain iterator.
However, the compiler is seeing the private version and complaining that it is private instead of using the public const version.
I understand that C++ will not overload on return type (in this case const_iterator and iterator) and thus it is choosing the non-const version since my object is not const.
Short of casting my object to const before calling begin() or not overloading the name begin is there a way to accomplish this?
I would think this is a known pattern that folks have solved before and would like to follow suit as to how this is typically solved.
class myObject {
public:
void doSomethingConst() const;
};
class myContainer {
public:
typedef std::list<myObject>::const_iterator const_iterator;
private:
typedef std::list<myObject>::iterator iterator;
public:
const_iterator begin() const { return _data.begin(); }
const_iterator end() const { return _data.end(); }
void reorder();
private:
iterator begin() { return _data.begin(); }
iterator end() { return _data.end(); }
private:
std::list<myObject> _data;
};
void myFunction(myContainer &container) {
myContainer::const_iterator itr = container.begin();
myContainer::const_iterator endItr = container.end();
for (; itr != endItr; ++itr) {
const myObject &item = *itr;
item.doSomethingConst();
}
container.reorder(); // Do something non-const on container itself.
}
The error from the compiler is something like this:
../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private
caller.cpp:2393: error: within this context
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private
caller.cpp:2394: error: within this context
Thanks.
-William
Bad idea to derive from std::list (it is not designed to be derived from).
Use a member variable of type std::list.
class myContainer
{
std::list<myObject> m_data;
public:
typedef std::list<myObject>::const_iterator myContainer::const_iterator;
private:
typedef std::list<myObject>::iterator myContainer::iterator;
public:
myContainer::const_iterator begin() const
{
return m_data.begin();
}
myContainer::const_iterator end() const
{
return m_data.end();
}
private:
myContainer::iterator begin()
{
return m_data.begin();
}
myContainer::iterator end()
{
return m_data.end();
}
};
I think your only option is to rename the private methods (if you need them in the first place).
In addition I believe you should rename the typedefs:
class MyContainer
{
public:
typedef std::list<Object>::const_iterator iterator;
typedef iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
typedef std::list<Object>::iterator _iterator;
_iterator _begin();
_iterator _end();
...
};
Containers are supposed to typedef both iterator and const_iterator. A generic function accepting a non-const instance of your container might expect to make use of the iterator typedef - even if it is not going to modify the elements. (For example BOOST_FOREACH.)
It will be fine as far as const correctness goes, because should the generic function actually try to modify the objects, the real iterator type (being a const_iterator) wouldn't let it.
As a test, the following should compile with your container:
int main()
{
myContainer m;
BOOST_FOREACH(const myObject& o, m)
{}
}
Note that m is not const, but we are only trying to obtain const references to the contained types, so this should be allowed.
You need to change the name of the private begin end. The compiler can't differentiate by only the return type
This works for me : note the _begin _end names
#include <list>
class myObject {};
class myContainer : private std::list<myObject> {
public:
typedef std::list<myObject>::const_iterator const_iterator;
private:
typedef std::list<myObject>::iterator iterator;
public:
myContainer::const_iterator begin() const {
return std::list<myObject>::begin();
}
myContainer::const_iterator end() const {
return std::list<myObject>::end();
}
private:
myContainer::iterator _begin() {
return std::list<myObject>::begin();
}
myContainer::iterator _end() {
return std::list<myObject>::end();
}
};
void myFunction(myContainer &container) {
myContainer::const_iterator aItr = container.begin();
myContainer::const_iterator aEndItr = container.end();
for (; aItr != aEndItr; ++aItr) {
const myObject &item = *aItr;
// Do something const on container's contents.
}
}
int main(){
myContainer m;
myFunction(m);
}
You might want to change the signature of your method Myfunction to this:
void myFunction(const myContainer &container)
because a const method would be called on a const object only. What currently is happening is that you are trying to call a non-const method which in your case is private.