I'm wondering about one thing. I've got class which has 1 overloaded member function:
class A{
public:
class const_iterator{};
class iterator : public const_iterator{};
iterator find(const K &key);
const_iterator find(const K &key) const;
};
Ad. iterator is inheriting from const_iterator, but it isn't adding anything.
What I want to do is, inside normal find call const find. Something like this:
typename A::iterator A::find(const K &key){
const_iterator it(find(key));
return (*(iterator*)&it);
}
I don't need different implementation of non-const find ATM. Is it possible to do something like this? Because now I'm getting into infinite loop, adding "A::" before find isn't changing anything.
In general, there’s no clean solution for this, unfortunately.
You can call the overloaded find by simply casting this to A const* – but the result will be of the wrong type (const_iterator rather than iterator) and there may not be a conversion between these in the general case (your (*(iterator*)&it) won’t work in your case).
But of course, in your special case, since you defined the two classes, you can define such a conversion by adding an appropriate constructor to iterator:
class iterator : public const_iterator {
iterator(const_iterator const& other) {
// Construct …
}
};
Then you can re-write your non-const find implementation as follows:
A::iterator A::find(const int &key){
const_iterator it(const_cast<A const*>(this)->find(key));
return static_cast<iterator>(it);
}
Incidentally, note the absence of typename in the return type. Since A::iterator isn’t a dependent name, you don’t need (and, at least in C++03, are not allowed to) use typename here.
const_cast<const A*>(this)->find(key);
Related
The code
Below is a downsized implementation of a class I'm having trouble with:
class Dummy{
public:
Dummy();
~Dummy();
void addItem(std::unique_ptr<Type>&& item);
private:
QVector<std::unique_ptr<Type>> collection;
}
The Type, in the code snippet above, is another class which supports move semantics.
Here's the implementation of the addItem member:
void Dummy::addItem(std::unique_ptr<Type>&& item){
if((std::find(collection.begin(), collection.end(), item) == colection.end()){
collection.push_back(std::move(item));
}
}
I use the class Dummy as follows:
Dummy myDummy;
std::unique_ptr<Type> item(new Type());
myDummy.addItem(sdt::move(item));
The problem
The compiler reports the following:
required from 'QVector<T>::iterator QVector<T>::begin()'
required from here
use of deleted function 'std::unique_ptr<_Tp,_Dp>::unique_ptr(const std::unique_ptr<_Tp,_Dp>&)'
Does this mean that I cannot iterate with the provided iterators over a QVector<std::unique_ptr<Type>> and hence cannot use std::find provided by the algorithms header?
I could use a range-base for for(auto const& other : collection) and implement the equality operator for Type in order to get the behaviour from std::find.
I'm failing to grasp where the example goes wrong.
The problem is that QVector copies (copy constructs) its elements when you:
Add them with push_back() function.
Get non-constant iterator to the container's end.
To avoid the second one you have to use rather const iterators, i.e. QVector::constBegin() and QVector::constEnd(), i.e.
if (std::find(collection.constBegin(), collection.constEnd(), item) == collection.constEnd()) {...}
To avoid copying on addition... hm, I advice using rather std::vector instead.
When defining my custom containers, it is more easy and very general (for me) making them iterable by just adding size() and []. This is, having the following member methods:
unsigned int size() const { . . . }
T & operator[] (unsigned int pos) { . . . }
In order to benefit from the STL algorithms, I provide an adaptor
from any container class having the above methods to an iterator valid for the STL functions.
With it, I can write easily things like
MyContainer<int, 5> mc;
IteratorFromContainer<MyContainer<int,5>, int> iter (&mc);
int i=1; for (auto & e : iter) { e = i++; }
for (auto e=iter.begin(); e!=iter.end(); ++e) { cout << (*e) << endl; }
int sum = std::accumulate(iter.begin(), iter.end(), 0);
int prod = std::accumulate(iter.begin(), iter.end(), 1, [](int a, int b) {return a*b;});
Surprisingly (to me) my adaptor (template) class works (the above sample code) equally well
with any of the following (1, 2, or 3):
template<typename Container, typename T>
// 1.
class IteratorFromContainer : public std::iterator<input_iterator_tag, T> {
// 2.
class IteratorFromContainer : public std::iterator<output_iterator_tag, T> {
// 3.
class IteratorFromContainer {
Why?. Should not the adaptor derive from std::iterator always?
What kind of iterator (what _tag) should I use, considering that the iterator is based in random access (size() and []) and has output and input capabilities: RandomAccess, ContinguousIterator?
Thanks
C++ uses a thing called duck-typing, which has awesome pros, and some really wierd cons. One of those cons are, if you break the interface contract, it might not notice until much later, if ever. When you use the for-loops, the compiler uses the iterator's copy constructor, operator++(), operator==(...) and operator*(), which you have, so it sometimes may work fine (I'm pretty sure GCC will point out the error in your options #2 & #3 though). I don't know the exact requirements for std::accumulate, but most likely they're similar. And so as long as you have those your code "works".
However, with options #2 and #3, you're breaking the "contract" about what it means to be an iterator. As such, the compiler or library may receive an update, and your code may stop working. The requirements for each iterator type depends on the type of iterator you're modeling, for more details see this page: How to implement an STL-style iterator and avoid common pitfalls?. However, the minimum requirements are you must have these operations:
iterator(const iterator&);
~iterator();
iterator& operator=(const iterator&);
iterator& operator++(); //prefix increment
reference operator*() const;
and also std::iterator_traits<IteratorFromContainer> must have these typedefs:
typedef ???? difference_type; //almost always ptrdif_t
typedef ???? value_type; //almost always T
typedef ???? reference; //almost always T& or const T&
typedef ???? pointer; //almost always T* or const T*
typedef ???? iterator_category; //usually std::forward_iterator_tag or similar
For simplicity, if you don't specialize std::iterator_traits yourself, it will check if your iterator has those typedefs, and if so, it will copy the ones from your iterator. std::iterator has these typedefs, and so if you inherit from it, you automatically have the typedefs, and so std::iterator_traits will automatically have them, so you'll meet the contractual guarantees. But inheriting from std::iterator is not necessary, you can add the typedefs yourself, or specialize iterator_traits.
Since you're working with operator[], it makes sense for you to use std::random_access_iterator_tag, which has many more requirements than those listed above. Again, see my other answer linked above for details on exactly what those members are.
Basically, I'm trying to write a base class that has a generic iterator in.
So apparently template virtual functions don't work, that's why I tried boost::any, but it is still not overloading Iterator's get() method (it keeps throwing the Exception defined below). I also can't seem to make it pure virtual because the compiler complains about 'virtual iterator begin() = 0;' (it says 'cannot create instance of abstract class Iterator').
I have very specific constraints that I have to / want to adhere to, so alternative solutions to the problem might be looked at, but probably can't be used.
Here is a part of the code:
template <class T, class C>
class Iterator
{
public:
virtual T& operator*() { T *t = boost::any_cast<T>(&get()); return *t; };
virtual boost::any& get() { throw new Exception("get not overridden!!"); };
//virtual boost::any& get() = 0;
protected:
C::iterator iter;
};
template <class T>
class VectorIterator: public Iterator<T, std::vector<T> >
{
public:
VectorIterator(std::vector<T>::iterator iterator): Iterator<T, std::vector<T> >(iterator) { };
virtual boost::any& get() { return *iter; };
};
template <class Value, class Container>
class Repository
{
public:
typedef Iterator<Value, Container> iterator;
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
class SomeRepository : public Repository<RandomClass, std::vector<RandomClass> >
{
public:
iterator begin() { return VectorIterator<RandomClass>(items.begin()); };
iterator end() { return VectorIterator<RandomClass>(items.end()); };
}
So, why isn't it working and (how) can I fix it?
PS: I know this is very similar to another question, but I couldn't exactly fit this into a comment and didn't really know where else I could put it.
UPDATE:
So I managed to figure something out by letting get() return a void (eww) pointer and forgetting about boost::any. But it still calls Iterator::get instead of VectorIterator::get (as was my original problem) (when I try to use something like *someRepository.begin()), does anyone know why?
You cannot initialize a boost::any& from *iter, much like you cannot initialize float& from a value of type int. In both case there is no actual object of the desired type to refer to.
You can change get to return boost::any (in which case the conversion from *iter will happen), but then your operator* has an issue in that the T it wants to refer to (again, reference type) needs to outlive the function call. One solution is to store the result of calling get somewhere, or to follow through with the same change to get by making operator* also return a value (T) rather than a reference (T&). Those would be value semantics, and not a 'shallow' view into the underlying container. Assigning to the result of operator*, assuming it's correct, would not affect the element of the container.
Another possibility is to make get return a boost::any that is guaranteed to store a shallow view into the element, e.g.
virtual boost::any get() { return &*iter; }
(return boost::ref(*iter); is another possibility)
Care must be then taken inside operator* to correctly restore the expected value, e.g. return *boost::any_cast<T*>(get()); (resp. return boot::any_cast<boost::reference_wrapper<T> >(get()).get();). This has reference semantics, where returning T& would be fine. Operations on the result of operator* could potentially affect elements of the container.
If you return Iterator in 'iterator begin()' (so returning by value), it will convert the return to Iterator, thus it will no longer be of type VectorIterator and obviously it will not call VectorIterator's get method (at least that's what I think). Returning by reference or pointer should work just fine.
Now I just need to figure out a workaround. Returning by reference won't work since I'm returning a local variable in VectorIterator::begin(). I suppose I'll have to return by pointer unless someone else has a better suggestion.
I would like to know if its possible to call a non-const member function from a const member function. In the example below First gives a compiler error. I understand why it gives an error, I would like to know if there is a way to work around it.
class Foo
{
const int& First() const
{
return Second();
}
int& Second()
{
return m_bar;
}
int m_bar;
}
I don't really want to discuss the wisdom of doing this, I'm curious if its even possible.
return (const_cast<Foo*>(this))->Second();
Then cry, quietly.
It is possible:
const int& First() const
{
return const_cast<Foo*>(this)->Second();
}
int& Second() { return m_bar; }
I wouldn't recommend this; it's ugly and dangerous (any use of const_cast is dangerous).
It's better to move as much common functionality as you can into helper functions, then have your const and non-const member functions each do as little work as they need to.
In the case of a simple accessor like this, it's just as easy to return m_bar; from both of the functions as it is to call one function from the other.
By the definition of const, a function should not modify the state of an object. But if it calls another non-const member, the object's state might get changed, so it's disallowed.
I know you said you didn't want to hear about this, but I think it's important for others that happen upon the question.
The restriction of const member methods are came from compile time. If you can fool the compiler, then yes.
class CFoo
{
public:
CFoo() {m_Foo = this;}
void tee();
void bar() const
{
m_Foo->m_val++; // fine
m_Foo->tee(); // fine
}
private:
CFoo * m_Foo;
int m_Val;
};
This actually abolishes the purpose of const member function, so it is better not to do it when design a new class. It is no harm to know that there is a way to do it,especially it can be used as an work-around on these old class that was not well designed on the concept of const member function.
Overload on const:
const int& Second() const
{
return m_bar;
}
You can add this method and keep the original non-const version.
iterators are similar in this and make an interesting study.
const iterators are often the base for 'non const' iterators, and you will often find const_cast<>() or C style casts used to discard const from the base class with accessors in the child.
Edit:
Comment was
I have a zip iterator where the const one inherits from the non-const
This would generally be the wrong inheritence structure (if your saying what I think you are), the reason being that children should not be less restrictive than parents.
say you had some algorithm taking your zip iterator, would it be appropriate to pass a const iterator to a non const ?
if you had a const container, could only ask it for a const iterator, but then the const iterator is derived from an iterator so you just use the features on the parent to have non const access.
Here is a quick outline of suggested inheritence following the traditional stl model
class ConstIterator:
public std::_Bidit< myType, int, const myType *, const mType & >
{
reference operator*() const { return m_p; }
}
class Iterator : public ConstIterator
{
typedef ConstIterator _Mybase;
// overide the types provided by ConstIterator
typedef myType * pointer;
typedef myType & reference;
reference operator*() const
{
return ((reference)**(_Mybase *)this);
}
}
typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;
I found myself trying to call a non-const member function that was inherited, but was actually const because of the API I was using. Finally I settled on a different solution: re-negotiate the API so that the function I inherit is properly const.
It won't always be possible to negotiate changes to others' functions, but doing so when possible seems cleaner and nicer than needing to use const_cast and it benefits other users as well.
OK, so I have two (completely unrelated, different project) classes using iterators now. One has iterator and reverse_iterator working as intended, and the other, current one has iterator and a semi-broken const_iterator (specifically, because const_iterator derives from iterator, the code LinkedList<int>::iterator i = const_list.begin() is valid and allows you to modify the const defined list...).
I intend to add all four types to this class... If I can.
How would I proceed to minimize copy/pasting code and changing only the return type? Create a base class like base_iterator to inherit from? Create an iterator or const_iterator and inherit from that? Inherit from some std:: class? If any of these cases are the "best" approach, what code goes where?
Perhaps none of the alternatives are good? I'm quite lost here, and can't find much reference material.
Any advice is appreciated, but please keep in mind that I'm new to the subject (both iterators and C++ in general, especially OOP). I've tried, in vain, to study the header files shipped with GCC - they're not exactly the tutorial I'm looking for.
Sometimes, blanket application of the so-called DRY rule (Don't Repeat Yourself, for those who aren't familiar) is not the best approach. Especially if you're new to the language (C++ and iterators) and OOP itself (methodology), there's little benefit in trying to minimise the amount of code you need to write right now.
I would implement the two iterators using appropriate code for each of them. Perhaps after you have more experience with the language, tools, and techniques, then go back and see whether you can reduce the amount of code by factoring out common code.
It's actually extremely simple.
First of all, take a look at Boost.Iterator library.
Second: you need to declare a base class (it's well explained in the example how to proceed) that will be similar to this one.
template <class Value>
class BaseIterator: boost::iterator_adaptor< ... > {};
You implement the operations to move your pointer around there. Note that because it's an adaptation over an already existing iterator, you can implement it with only a few strokes. It's really impressive.
Third, you simply typedef it with the const and non-const versions:
typedef BaseIterator<Value> iterator;
typedef BaseIterator<const Value> const_iterator;
The library explictly show you how to make the const_iterator version be constructible from the iterator version.
Fourth, for the reverse thing, there is a special reverse_iterator object, that is built on a regular iterator and move backwards :)
All in all, a really elegant and yet fully functional way of defining iterators on custom classes.
I regularly write my own container adaptors, and it's less about DRY than simply saving myself some typing!
Make iterator derive from const_iterator instead of the other way around. Use const_cast appropriately (as an implementation detail, unexposed to users). This works very well in the simple cases and models that "iterators are const_iterators" directly.
When this starts to require clarification comments in your code, then write separate classes. You can use localized macros to generate similar code for you, to avoid repeating the logic:
struct Container {
#define G(This) \
This& operator++() { ++_internal_member; return *this; } \
This operator++(int) { This copy (*this); ++*this; return copy; }
struct iterator {
G(iterator)
};
struct const_iterator {
G(const_iterator)
const_iterator(iterator); // and other const_iterator specific code
};
#undef G
};
That the macro is scoped/localized is important, and, of course, only use it if it actually helps you—if it results in less readable code for you, type it out explicitly.
And about reverse iterators: you can use std::reverse_iterator to wrap your "normal" iterators in many cases, instead of rewriting them.
struct Container {
struct iterator {/*...*/};
struct const_iterator {/*...*/};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
};
LinkedList<int>::iterator i = const_list.begin() What does your begin method look like? By studying the STL you can see that containers define two such methods with the following signatures:
const_iterator begin() const;
iterator begin();
You should not have a problem getting an iterator from an object qualified as const. I don't think DRY applies here.
Once I used the following approach:
make a template class common_iterator
add typedefs for "iterator" and "const_iterator"
add to "common_iterator" a constructor taking "iterator" type
For "iterator" the additional constructor will replace default copy constructor, in my case it was equivalent to default copy constructor.
For "const_iterator" it will be an additional constructor which allows to construct "const_iterator" from "iterator"
A more concrete version of what maxim1000 suggested:
#include <type_traits>
template<typename Container, bool forward>
class iterator_base
{
public:
using value_type =
typename std::conditional<std::is_const<Container>::value,
const typename Container::value_type,
typename Container::value_type>::type;
iterator_base() { }
// For conversions from iterator to const_iterator.
template<typename U>
iterator_base(const iterator_base<U, forward>& other)
: c(other.c)
{
// ....
}
value_type& operator*() const
{
// ...
}
iterator_base& operator++()
{
if (forward)
{
// ...
}
else
{
// ...
}
}
iterator_base& operator++(int)
{
iterator_base copy(*this);
++*this;
return copy;
}
private:
Container* c = nullptr;
// ...
};
using iterator = iterator_base<self_type, true>;
using const_iterator = iterator_base<const self_type, true>;
using reverse_iterator = iterator_base<self_type, false>;
using const_reverse_iterator = iterator_base<const self_type, false>;