C++11 iterator interface - c++

Is it possible to create in C++11 a function, which will accept any iterator as input argument in particular stl containers like vector or list?
I want to write something like
void f(iterator<int> i){
for (auto el : i)
cout << el;
}
int main(){
vector<int> v;
list<int> l;
...
f(v);
f(l);
}
Is it possible?

If you want your function to accept an iterator, then you cannot use the for (auto i: cont) syntax. Indeed, this new range-based for syntax wants the container, not an iterator.
Then, your can easily make your function a function template, passing the container.
template <class CONT>
void f(CONT &cont){
for (auto el : cont)
cout << el;
}
If you want to keep passing iterators, then you'll have to go the template way too, but you have to pass two iterators as arguments. One for the first, another for the last (just like the algorithm does).
template <class IT>
void f(IT first, IT last) {
for ( ; first!=last ; ++first)
cout << first;
}

No. You can write a function template that accepts any iterator as parameter, but not a function.
If you had a class that did type erasure for iterators then you could take that as a parameter. Here's an article and code for iterator type erasure.

There is a boost::any_iterator somewhere. But the Standard does not provide one.

If you are looking for a way to return a mostly unspecified iterator type (e.g. because the function signature in a base class can't fix the exact type of the iterator yet), you could have a look at C++: "Iterable<T>" interface

Related

How to declare a reference to std algorithm?

I am trying to add a reference to std algorithm. How can I edit my code to make it working?
double f(const std::vector<double> &arr, bool maxElem)
{
auto me = maxElem ? std::max_element : std::min_element;
//...
x = me(arr.begin(), arr.end());
//...
}
Your functions are template functions so you have to specify the template parameter. In this case, using a std::vector you need to pass them iterators:
Also, to cope with different potential overloads of the functions we should cast them to the type we require (thnx to #ChristianHackl):
double f(const std::vector<double>& arr, bool maxElem)
{
// deduce the iterator parameter types
using Iterator = decltype(arr.begin());
// select the overload type
using Overload = Iterator(*)(Iterator, Iterator);
auto me = maxElem
? static_cast<Overload>(std::max_element<Iterator>)
: static_cast<Overload>(std::min_element<Iterator>);
// need to dereference this because `me` returns an iterator
return *me(arr.begin(), arr.end());
}
Also note I dereference the return value from me() because it is an iterator (like a pointer).
Of course if your vector is empty that will dereference an invalid location so I recommend putting in a check:
double f(const std::vector<double>& arr, bool maxElem)
{
// Avoid Undefined Behavior
if(arr.empty())
throw std::runtime_error("empty vector not allowed");
// deduce the parameter types
using Iterator = decltype(arr.begin());
// select the overload type
using Overload = Iterator(*)(Iterator, Iterator);
auto me = maxElem
? static_cast<Overload>(std::max_element<Iterator>)
: static_cast<Overload>(std::min_element<Iterator>);
// need to dereference this because `me` returns an iterator
return *me(arr.begin(), arr.end());
}
Like this:
if (maxElem)
return std::max_element(arr.begin(), arr.end());
else
return std::min_element(arr.begin(), arr.end());
You could probably obtain a reference to the template specialisation of each "algorithm" you're trying to use, but due to the need to specify template arguments it would be messy and verbose, and thus a false economy. It may also carry a performance penalty (ruining inlineability).
It doesn't really make sense for f to behave like this in the first place; try to make your functions do one thing well. Arguably, their underlying semantics shouldn't depend on an argument like this.

C++ Iterator Syntax

I'm confused about C++ syntax for instantiating an iterator namely (for a list),
std::list<C++ class object>::iterator iterator_name;
What is up with std::list before the ::iterator, does this mean iterator is defined in a namespace list in std?
Sorry if this question is obvious or trivial, but I've finally convinced myself to use "std" more and now I'm finding some of the syntax to be a bit confusing.
It is a member type. The std::list template class is (conceptually) defined as follows:
template<typename T>
class list {
public:
using iterator = /* some implementation-dependent type */
};
Hence, regardless of the standard library implementation you are using, you know that, for some T, std::list<T>::iterator is an alias for the type implementing the list iterator.
std::list is a template class. Saying std::list< T >::iterator means you have an iterator of a list and not an iterator of a vector (std::vector< T >::iterator) or any other container.
If you find the name too long you can also use auto if you initialize the iterator:
auto it = myList.begin();
std::list<> is not a namespace, it's a template class, and iterator is a type inside this template. To access it, you use the double colons.
iterator is an embedded member type of the class template std::list. std is the Standard Library namespace.
The scope resolution operator :: is used to access names in namespaces and classes, the documentation (or source code) should be consulted to get an exact definition of the name.
In this case, iterator is an embedded type for most Standard Library containers. It is often also used for containers that are modelled on the Standard Library, but it is not a general requirement for any given class.
std::list::iterator obj_iterator; // It means declaring pointer obj_iterator of type std::list
//simple code snippet
std::list<int> intList; // declaring intList of type std::list<int>
for (int i = 0; i < 10; ++i) {
intList.push_back( 1 << i );
}
std::list<int>::iterator int_iterator; //declaring pointer int_iterator of type std::list<int>
for (int_iterator = intList.begin(); int_iterator != intList.end(); ++int_iterator) {
std::cout << *int_iterator; // using of int_iterator
}`

C++ generic iterator

I'm not sure if the answers I was able to find are the easiest way to do what I need. The simple template that I would know how to modify into a full solution to my problem would be code that accomplishes the following:
Takes as input two iterators pointing to the beginning and end of an iterable container (vector, list...) containing things of value type T.
Returns a std::vector<T> containing an element-by-element copy of the input container in whatever order accomplished by iterating the input container from beginning to end.
Something non-functioning would be like follows:
template<typename Iterator, typename T>
std::vector<T> dumb_copy(Iterator first, Iterator last) { ... }
Problem is that I would need the compiler to somehow check that I'm given iterators pointing to something of type T.
I'm currently learning C++ and writing as practice the most generic implementations of certain algorithms that I can think of, so I want to get the best practices right from the start. If there's an easy way of doing this using C++11 constructs, that's fine with me.
You can simply use traits to remove the T type completely, allowing it to be determined automatically:
template <typename Iterator>
std::vector<typename std::iterator_traits<Iterator>::value_type>
dumb_copy(Iterator first, Iterator last)
{
std::vector<typename std::iterator_traits<Iterator>::value_type> copy;
// Populate the copy vector
return copy;
}
In particular, note that std::iterator_traits has a specialization when the iterator type is a pointer, so this will allow your function to "just work" even when it is passed pointers instead of "true" iterator objects.
You don't need to do this because the standard library containers already work this way. So you can create a std::vector from two iterators directly:
#include <string>
#include <vector>
#include <iostream>
int main()
{
std::string s = "hello"; // iterable container
// construct a vector using two iterators
std::vector<std::string::value_type> v(s.begin(), s.end());
// check the results
for(unsigned i = 0; i < v.size(); ++i)
std::cout << v[i];
std::cout << '\n';
}
You can just create a std::vector<T> with a type matching the result of *it for one of the iterators:
#include <type_traits>
#include <vector>
template <typename Iterator>
auto dump_copy(Iterator begin, Iterator end)
-> std::vector<typename std::decay<decltype(*begin)>::type> {
return std::vector<typename std::decay<decltype(*begin)>::type(begin, end);
}
With C++14 you can replace typename std::decay<X>::type by std::decay_t<X>.

C++: overloading list.end() and list.begin() methods for constant iterators

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.

Is there a C++ equivalent to Java's Collection interface for STL container classes?

I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements). Unfortunately it looks like there is no standard way of doing this.
First solution which comes to my mind is an interface (let's call it CollectionInterface) implemented by classes that will wrap STL containers. so the function declaration would look like:
f(const CollectionInterface * collection);
Or, I was thinking about method template, which has an advantage that it keeps binding at compilation time:
template <class CONTAINER> void f(const CONTAINER & collection);
Which way do you think is better?
ForwardIterator? This is a type of InputIterator (or OutputIterator) that also allows multi-pass algorithms (incrementing it does not invalidate prior values).
Iterators (which are quite different from Java iterators) are the central thread unifying C++ collections. For examples of algorithms working on them (and associated iterator type requirements), you can start with <algorithm>. In particular, search provides an example of using ForwardIterator. It finds the first occurrence within the range [first1, last1] of the sequence defined by the range [first2, last2). These are all objects meeting the requirements of ForwardIterator.
You can also write methods that accept the entire container instead of a reference if that's the way you want to handle things. Iterators into standard library containers are all provided via the member functions begin() and end(), or in some cases rbegin() and rend() for iterating backwards. The way templates work, you don't have to create an actual interface type that objects derive from; the requirements are instead inferred by the object is used.
template<typename Container> void Function(const Container& c) {
for(typename Container::const_iterator i = c.begin(), end = c.end(); i != end; ++i)
//do something
}
Passing iterators provide more flexibility when using the functions, particularly in that not all iterators come from containers with explicit begin() and end() functions, and you can provide whatever explicit subrange you want. But sometimes this method is appropriate.
I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements).
Pass iterators. Here is an example for implementation and use:
template <typename Iter>
void function(Iter begin, Iter end)
{
for (Iter it = begin; it != end; ++it)
{
std::cout << *it << std::endl;
}
}
int main()
{
std::string array[] = {"hello", "array", "world"};
function(array, array + 3);
std::vector<std::string> vec = {"hello", "vector", "world"};
function(vec.begin(), vec.end());
}
Note that in many cases, you don't actually need to write the function, but you can compose it using the library facilities instead and then simply apply std::for_each on that. Or even better, use a preexisting algorithm like std::accumulate or std::find_if.