there is insert iterator in database template library or other library, Can someone tell me how it work ?
Thanks!
It is a template class so you should be able to look it up in the implementation.
However, the idea is that it stores an iterator (current location) and a reference (pointer) to a container (that is being inserted in). Then it overloads operator= like this:
insert_iterator& operator= (typename Container::const_reference value)
{
m_iter = m_container->insert(m_iter, value);
++m_iter;
return *this;
}
So it requires a container that supports the insert method and at least a forward iterator, and has the standard typedefs (const_reference or perhaps value_type), so it can declare the right-hand type of its operator=.
The other output iterator operators (*, ++) just return *this.
Related
The code bellow (-std=c++11) according to a "naive" view should work.
Instead it doesn't (should be known and understood why it doesn't).
Which is the shortest way of modifying the code (overloading &) in order to make it behave according to the "naive" view ?
Shouldn't that be given as an option during stl object creation (without writting too much) ?
#include <iostream>
#include <vector>
int main(int argc, char **argv)
{ std::vector<int> A{10,20,30};
auto i=A.begin();
auto j=&*i;
std::cout<<"i==j gives "<<(i==j)<<std::endl;
return 0;
}
The problem cannot be solved. There are three reasons it cannot be solved.
First problem
The operator & you need to overload is the operator & for the element type of the vector. You cannot overload operator & for arbitrary types, and in particular you can't overload it for built-in types (like int in your example).
Second problem
Presumably you want this to work for std::vector, std::array, and built-in arrays? Also probably std::list, std::deque, etc? You can't. The iterators for each of those contains will be different (in practise: in theory, some of them could share iterators, but I am not aware of any standard library where they do.)
Third problem
If you were prepared to accept that this would only work for std::vector<MyType>, then you could overload MyType::operator & - but you still couldn't work out which std::vector<MyType> the MyType object lives in (and you need that to obtain the iterator).
First of, in your code snippet i deducts to std::vector<int>::iterator and j deducts to int*. The compiler doesn't know how to compare std::vector<int>::iterator against int*.
For this to work out, you could provide an overloaded operator== that would compare vector iterators against vector value type pointers in the following manner:
template<typename T>
bool operator==(typename std::vector<T>::iterator it, T *i) {
return &(*it) == i;
}
template<typename T>
bool operator==(T *i, typename std::vector<T>::iterator it) {
return it == i;
}
Live Demo
This shouldn't work - not even "accoding to a 'naive"' view". Eventhough every pointer is an iterator the reverse is not necessarily true. Why would you expect that to work?
It would work under two scenarios:
The iterator of the std::vector<T> implementation is actually a T*. Then your code would work since decltype(i) == int* and decltype(j) == int*). This MAY be the case for some compilers but you shouldn't even rely on it if it was true for your compiler.
The dereference operator does not return an object of type T but rather something that is convertible to T and has an overloaded operator& which gives the iterator back. This is not the case for very good reasons.
You could -as other have suggested- overload operator== to check whether both indirections (pointer and iterator) reference the same object but I suspect that you want the address of operator to give you back the iterator which cannot be accomplished if the iterator is not a pointer because the object type which is stored in the vector has no notion of vector/iterator or whatever.
The problem isn't in the equality operator, what I need is to define the dereference operator to give an iterator
You can't. The dereference operator in question is std::vector<int>::iterator which is part of the standard library and you can (and should not) manipulate it.
Note that since C++11 in a std::vector<T, A>,
value_type is T and
reference is T&.
Furthermore, the following is true:
All input iterators i support *i which gives a value of type T which is the value type of that iterator.
The iterator of std::vector<T> is required to have T as its value type.
An iterator of std::vector<T> is an input iterator.
I'm implementing an iterator for an adaptor range which lazily evaluates something on an original range. This means: dereferencing the iterator should dereference the underlying iterator and apply some operation on the result, then returning the result of that operation.
T operator*() const {
return someOperation(*original_iterator);
}
How can I implement operator-> analogous to this operator*? When looking at other iterator's implementations, they usually return a T*. But I can't return a pointer, since the "pointed to object" is a temporary, computed on-the-fly.
What's the usual guidance in this case? May I simply return a T instead?
Although I personally don't need this operator (I could also use (*i).m instead of i->m and the standard algorithms don't seem to depend on -> either), I'd like my iterator to strictly conform to the ForwardIterator concept which is a specialization of InputIterator which requires the implementation of this operator.
The simplest way is to just use Boost.Iterators to implement your iterators, which takes care of the tricky code.
But the technique used by Boost.Iterators isn't that complicated. It looks like this:
template <typename T>
class proxy_holder {
T t;
public:
proxy_holder(const T& t) : t(t) {}
T* operator ->() const { return &t; }
};
class the_iterator {
// ...
proxy_holder<my_proxy> operator ->() const {
return proxy_holder<my_proxy>(**this);
}
};
This relies on the fact that arrow operators get chained, i.e. if one arrow operator returns something that isn't a raw pointer, the arrow operator is called on that thing in turn, until you get to a pointer.
I am making my own STL-like container - tree with any number of children
template<typename Type>
class Node
{
Type value;
Iterator AddChild(const Type & value);
void Remove(const Iterator & where);
...
};
I decided that iterator's operator* should return value of current node, but what should return operator->? Currently, it returns Node<Type>* and it very useful in such situations
Node<int>::Iterator it = tree.begin();
it->AddChild(4);
But my mentor said me, that operator-> should return Type*. What is STL-like way to access Node's methods? Something like it.Ref().MyMethod() doesn't look good.
Your mentor is right, the return type of operator->() should be Type*.
The big idea behind iterators is that they are just smart pointers to some locations inside the container. You can alter the value stored at that location (by assigning to *it) or access its members, but to do more drastic (i.e. structural) changes to container contents, you have to have direct access to the container itself.
That's why in STL, there are no node's methods. Instead, there're container's methods (and also algorithms) that accept iterators as arguments.
In other words, the STL way of doing what you're trying to do is:
Node<int>::Iterator it = tree.begin();
tree.AddChild(it, 4);
operator-> should return YourTree::value_type* and operator* should return YourTree::value_type&. (Actually a YourTree::pointer and YourTree::reference, but these are normally just aliases for * and & of the value type). Note the consistency. Without it, the standard algorithms will not work.
It is up to you to decide what the value_type is. It could well be Node if you want. This however can be confusing and hard to implement consistently. I would leave it as Type.
The programmer expects it->method to be equivalent to (*it).method, so the operator-> should return pointer to the same thing that operator* returns reference to. Normally that should be the value of the iterator, because that's the expected way to get at the value.
You can expose methods of the node as methods of the pointer, i.e. called as it.method, but it's somewhat confusing and in most cases it would require extra data in the iterator compared to methods of the container taking iterator as argument. That's why STL always uses methods of the container taking iterator. E.g. container.insert(iterator, value) inserts value after iterator.
Say I'm making a function to copy a value:
template<class ItInput, class ItOutput>
void copy(ItInput i, ItOutput o) { *o = *i; }
and I would like to avoid the assignment if i and o point to the same object, since then the assignment is pointless.
Obviously, I can't say if (i != o) { ... }, both because i and o might be of different types and because they might point into different containers (and would thus be incomparable). Less obviously, I can't use overloaded function templates either, because the iterators might belong to different containers even though they have the same type.
My initial solution to this was:
template<class ItInput, class ItOutput>
void copy(ItInput i, ItOutput o)
{
if (&*o != static_cast<void const *>(&*i))
*o = *i;
}
but I'm not sure if this works. What if *o or *i actually returns an object instead of a reference?
Is there a way to do this generally?
I don't think that this is really necessary: if assignment is expensive, the type should define an assignment operator that performs the (relatively cheap) self assignment check to prevent doing unnecessary work. But, it's an interesting question, with many pitfalls, so I'll take a stab at answering it.
If we are to assemble a general solution that works for input and output iterators, there are several pitfalls that we must watch out for:
An input iterator is a single-pass iterator: you can only perform indirection via the iterator once per element, so, we can't perform indirection via the iterator once to get the address of the pointed-to value and a second time to perform the copy.
An input iterator may be a proxy iterator. A proxy iterator is an iterator whose operator* returns an object, not a reference. With a proxy iterator, the expression &*it is ill-formed, because *it is an rvalue (it's possible to overload the unary-&, but doing so is usually considered evil and horrible, and most types do not do this).
An output iterator can only be used for output; you cannot perform indirection via it and use the result as an rvalue. You can write to the "pointed to element" but you can't read from it.
So, if we're going to make your "optimization," we'll need to make it only for the case where both iterators are forward iterators (this includes bidirectional iterators and random access iterators: they're forward iterators too).
Because we're nice, we also need to be mindful of the fact that, despite the fact that it violates the concept requirements, many proxy iterators misrepresent their category because it is very useful to have a proxy iterator that supports random access over a sequence of proxied objects. (I'm not even sure how one could implement an efficient iterator for std::vector<bool> without doing this.)
We'll use the following Standard Library headers:
#include <iterator>
#include <type_traits>
#include <utility>
We define a metafunction, is_forward_iterator, that tests whether a type is a "real" forward iterator (i.e., is not a proxy iterator):
template <typename T>
struct is_forward_iterator :
std::integral_constant<
bool,
std::is_base_of<
std::forward_iterator_tag,
typename std::iterator_traits<T>::iterator_category
>::value &&
std::is_lvalue_reference<
decltype(*std::declval<T>())
>::value>
{ };
For brevity, we also define a metafunction, can_compare, that tests whether two types are both forward iterators:
template <typename T, typename U>
struct can_compare :
std::integral_constant<
bool,
is_forward_iterator<T>::value &&
is_forward_iterator<U>::value
>
{ };
Then, we'll write two overloads of the copy function and use SFINAE to select the right overload based on the iterator types: if both iterators are forward iterators, we'll include the check, otherwise we'll exclude the check and always perform the assignment:
template <typename InputIt, typename OutputIt>
auto copy(InputIt const in, OutputIt const out)
-> typename std::enable_if<can_compare<InputIt, OutputIt>::value>::type
{
if (static_cast<void const volatile*>(std::addressof(*in)) !=
static_cast<void const volatile*>(std::addressof(*out)))
*out = *in;
}
template <typename InputIt, typename OutputIt>
auto copy(InputIt const in, OutputIt const out)
-> typename std::enable_if<!can_compare<InputIt, OutputIt>::value>::type
{
*out = *in;
}
As easy as pie!
I think this may be a case where you may have to document some assumptions about the types you expect in the function and be content with not being completely generic.
Like operator*, operator& could be overloaded to do all sorts of things. If you're guarding against operator*, then you should consider operator& and operator!=, etc.
I would say that a good prerequisite to enforce (either through comments in the code or a concept/static_assert) is that operator* returns a reference to the object pointed to by the iterator and that it doesn't (or shouldn't) perform a copy. In that case, your code as it stands seems fine.
Your code, as is, is definitly not okay, or atleast not okay for all iterator categories.
Input iterators and output iterators are not required to be dereferenceable after the first time (they're expected to be single-pass) and input iterators are allowed to dereference to anything "convertible to T" (ยง24.2.3/2).
So, if you want to handle all kinds of iterators, I don't think you can enforce this "optimization", i.e. you can't generically check if two iterators point to the same object. If you're willing to forego input and output iterators, what you have should be fine. Otherwise, I'd stick with doing the copy in any case (I really don't think you have another option on this).
Write a helper template function equals that automatically returns false if the iterators are different types. Either that or do a specialization or overload of your copy function itself.
If they're the same type then you can use your trick of comparing the pointers of the objects they resolve to, no casting required:
if (&*i != &*o)
*o = *i;
If *i or *o doesn't return a reference, no problem - the copy will occur even if it didn't have to, but no harm will be done.
I'm still trying to implement my own version of LinkedList class and now I have problems with overloading methods for constant iterators. For example, when I try to print out list using this code:
cout << "citer:" << endl;
for (UberList<int>::CIter it = ulist.begin(); it != ulist.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
I have these errors:
Error E2034 UberList2.cpp 532: Cannot convert 'UberList<int>::Iter' to 'UberList<int>::CIter' in function main()
Error E2094 UberList2.cpp 532: 'operator!=' not implemented in type 'UberList<int>::CIter' for arguments of type 'UberList<int>::Iter' in function main()
so as far as I understood, it means that those usual end and begin iterator methods are used. Here's how these methods are declared in my class:
Iter begin();
Iter end();
CIter begin() const;
CIter end() const;
and
template<class T>
typename UberList<T>::Iter UberList<T>::begin()
{
Iter it;
it.curr = head;
return it;
}
template<class T>
typename UberList<T>::Iter UberList<T>::end()
{
Iter it;
it.curr = tail->next;
return it;
}
template<class T>
typename UberList<T>::CIter UberList<T>::begin() const
{
CIter it;
it.ccurr = head;
return it;
}
template<class T>
typename UberList<T>::CIter UberList<T>::end() const
{
CIter it;
it.ccurr = tail->next;
return it;
}
Is there any way I can force my program to use these const methods for constant iterators instead of usual ones? I'd be glad to hear any advice.
Oh and here's the code of my class in one file just in case: http://pastebin.com/Jbvv5Hht
You should provide a conversion from Iter to CIter. Standard containers do (Table 65, in 23.1 "Container requirements", says that X::iterator is convertible to X::const_iterator)
The caller can ensure that the const overload is called by using a const reference, but you shouldn't force them to do that, because they will have to write something like:
UberList<int>::CIter it = static_cast<const UberList<int> &>(ulist).begin()
If you provide the "required" conversion then there's no need for your caller to do anything special: your original code will work, just as it does for standard containers.
Some more comments to the OP's code. Consider separating that gigantic uberl33tlist class and break it up into smaller files. Seeing all those friends class declaration is making me rather uncomfortable. There are also some tricky semantics When you're using stuff like
friend class UberList;
friend class CIter;
In some cases those statements also end up forward declaring those classes if they don't exist yet. There's also something not quite right looking about your assignment operator here:
UberList<T> operator = (const UberList<T>& OL)
{
UberList<T> NL = new (OL);
return NL;
}
Also in your main you have
it2++;
ulist.insertAfter(b, it2);
//...
You're using postfix operator ++ for it2 but didn't implement that your iterator class. Borland accepts it by using the prefix instead but gives a warning. Gcc actually flags that as an error and rejects the code. Might want to look into that
Sigh: there's a level of hackery here designed to hide the fact that conceptually what you want to do cannot be done automatically in C++ because it doesn't understand variance. Some other languages (including Ocaml) do.
If you have a functor (that's a template class to C++ programmers), the question is how it and various functions behave with a variance of the parameter, such as a conversion from T to T const. What you really want is this:
List<T> --> List<T const>
in other words you want the List functor to be covariant. But no, it isn't .. so actually the List template isn't a functor at all, because functors must be structure preserving and the conversion isn't reflected as required. In turn this means either C++ templates are broken OR the concept of const is broken, because a type system that doesn't support parametric polymorhism is broken by specification :)
Providing "const_iterator" does not solve this problem, it simply patches up the break. Where is the volatile and const_volatile version? How about double indirections?
If you don't understand double indirections: consider a tree of vectors of T, that's two templates:
Tree<Vector<T>>
The best solution here is to give up supporting const_iterator. Just don't bother. It's confused anyhow: how about "const vector"? What's that? A vector you can't make longer but it still allows you to write the elements?
The actual requirement is that transforms commute, for example:
vector<T> const == vector<T const>
[or they anti-commute if the transform is contra-variant]
The fact this doesn't happen shows that vector isn't functorial, in other words, templates can't be used effectively for parametric polymorphism. If you want to really get your knickers tied in a knot consider templates with function arguments and ask about the variance of the function's return type and parameters, and how this might impact the container. A good example is how to compose a two functions so they work on a pair. What if they're mutators, how does "const" work then?
You need
teamplate<class T> bool operator!=(UberList<T>::CIter,UberList<T>::CIter);
It's using the regular begin method because the variable is not const. So one way of fixing it is to make another (reference) variable that is const:
UberList<int> const & culist = ulist;
for (UberList<int>::Citer it = culist.begin(); ...)
Alternatively, use a const_cast.