using the `auto` keyword with STL iterators - c++

I'm following this tutorial for using the auto keyword with STL iterators.
It says that this syntax is OK for C++ 11.
vector<int> vec;
auto itr = vec.iterator(); // instead of vector<int>::iterator itr
However, I get this compile error when I try it?
error: invalid use of ‘std::vector::iterator’

The tutorial is wrong. iterator is a type member, not a function member, in all the collection classes. It is the return type of some of vector's member functions
What the tutorial probably means to write is
vector<int> vec;
auto itr = vec.begin(); // itr is of type std::vector<int>::iterator

Related

Iterators comparisions in STL

Below is text from Scott Meyers Effective STL regarding iterators Item 26.
typedef deque<int> IntDeque; //STL container and
typedef lntDeque::iterator Iter; // iterator types are easier
typedef lntDeque::const_iterator Constlter; // to work with if you
// use some typedefs
Iter i;
Constlter ci;
… //make i and ci point into
// the same container
if (i == ci ) ... //compare an iterator
// and a const_iterator
All we're doing here is comparing two iterators into a container, the kind of comparison that's the bread and butter of the STL. The only twist is that one object is of type iterator and one is of type const_iterator. This should be no problem. The iterator should be implicitly convened into a const_iterator. and the comparison should be performed between two const_iterators.
With well-designed STL implementations, this is precisely what happens, but with other implementations, the code will not compile. The reason is that such implementations declare operator== for const_iterators as a member function instead of as a non-member function, but the cause of the problem is likely to be of less interest to you than the workaround, which is to swap the order of the iterators, like this:
if (ci == i)... // workaround for when the
// comparison above won't compile
My question on above
Why author mean only const_iterator member function is called, it is also possible iterator member function is called for operator == ?
The issue here is that the comparison operators compare iterator with iterator and const_iterator with const_iterator. If the operators are non-member functions the compiler will find the conversion from iterator to const_iterator and call the const_iterator comparison function. If the comparison operator is a member function it will be called on the lhs which, in the example, is an iterator and there is no way to convert a const_iterator to an iterator. What the workaround does is to put the const_iterator as lhs and since iterator can be converted to const_iterator the comparison compiles.

How to properly initialize a vector from std::vector<>

When I compile the following code (using the -std=c++11 compiler flag), I get the (only) error message: " 'vec' is not a class, namespace or enumeration".
#include <vector>
#include <iterator>
int main(){
std::vector<int> vec(10,1);
vec::iterator it;
return 0;
}
As I do not get any other error message, to me this means that some object called 'vec' has been initialized, but not as a vector, but as something else which is not a class and for which the scope operator can therefore not be used.
As far as I understood it, I used the following constructor (http://en.cppreference.com/w/cpp/container/vector/vector):
vector(size_type count,
const T& value,
const Allocator& alloc = Allocator());
Where it says that this constructor "Constructs the container with count copies of elements with value value", so I expect to have created a vector with 10 copies of "1", but I must have misunderstood something, hence the problem.
Where did my reasoning go wrong and where does the error in the above code stem from?
The scope operator is used for accessing elements within a namespace or class. vec isn't a class but an object. You have to write std::vector<int>::iterator. You could also deduce a type of a variable by using auto: auto it = vec.begin() equals to std::vector<int>::iterator it = vec.begin()
Your initialization of the vector is fine. But in order to refer to the iterator type, you need to use the vector's type and not an object:
std::vector<int>::iterator it;

Why can template parameter be deduced only in one case?

Why does the following code compile for the line using a non-const iterator but fails for the const iterator (using Visual Studio 2008) ?
#include <vector>
using std::vector;
int main(int argc, char* argv[])
{
vector<int> test;
test.push_back(1);
test.push_back(2);
vector<int>::const_iterator cit = test.end();
std::distance(test.begin(), cit); // error: template parameter is ambiguous
vector<int>::iterator it = test.end();
std::distance(test.begin(), it);
return 0;
}
Note: In Visual Studio 2008 there is no vector member function cbegin() to avoid the ambiguousness, but an overloaded begin() method:
iterator begin()
{ // return iterator for beginning of mutable sequence
return (iterator(_Myfirst, this));
}
const_iterator begin() const
{ // return iterator for beginning of nonmutable sequence
return (const_iterator(_Myfirst, this));
}
Note: In Visual Studio 2008 there is no vector member function cbegin() to avoid the ambiguousness, but an overloaded begin() method:
I think the compiler always picks the non-const overload for a non-const objects, and the const method only for const objects.
Calling
std::distance(test.begin(), cit);
doesn't look at the overload set for begin and the type of cit, and figure out whether it can make a match. It resolves the overload first (to the non-const version), and hence fails.
The cleanest way to express your intent that will also work for the compiler is probably:
vector<int> const &cref = test;
vector<int>::const_iterator cit = cref.end();
std::distance(cref.begin(), cit);
The template distance takes one single argument, distance<T>(T first, T last). Since test.begin() has type iterator and cit has type const_iterator, the template argument cannot be deduced.
You can either use test.cbegin() to get a guaranteed const_iterator, or otherwise say static_cast<std::vector<int> const &>(test).begin().
(This is the same as if you had max<T>(T x, T y) and tried to say max(1, 2U) -- it wouldn't compile because it's ambiguous.)
The function template std::distance only takes a single template
argument, which must be the same for both function arguments. The
return type of test.begin() is simply iterator, not
const_iterator, so the types of the function arguments are different.
The compiler deduces std::vector<int>::iterator for the first, and
std::vector<int>::const_iterator for the second, so the deduction
fails. Template argument deduction does not take into account
possible conversions, except for the simplest conversions.
There are many ways to work around thing, but they all have noticeable
drawbacks. (That's probably why the committee added the cbegin and
cend functions.) For the moment, your best bet is probably just to forgo the const, and use iterator for both.
distance must have template arguments of the same time. In this case it is _Vector_const_iterator. There are two overloads of begin: const and non-const. const-version produces _Vector_const_iterator, but another produces _Vector_iterator. _Vector_iterator inherits from _Vector_const_iterator.
So, both const and non-const overloads of begin are capable of producing _Vector_const_iterator and they both can be picked for non-const object, i.e. compiler gets confused.
This is how I got it to compile:
std::distance(((const vector<int>&)test).begin(), cit);

STL algorithms and const_iterators

Today I wrote a small predicate to find matching symbols in a container.
But I'm faced to a problem: I want to use this predicate in a std::find_if call inside a const-method of a class, searching in a container that is a member of this class.
But I just noticed that neither std::find nor std::find_if are able to operate on const_iterators !
I checked on some C++ references and it seems there is no version of std::find or std::find_if that accept/return const_iterators. I just can't understand why, since from what I've seen, there is no way that these algorithms could modify the object referenced by the iterator.
Here is how is documented std::find in the SGI implementation:
Returns the first iterator i in the
range [first, last) such that *i ==
value. Returns last if no such
iterator exists.
std::find and std::find_if can definitely operate on *::const_iterator for a given container. Are you by chance looking at the signatures of those functions, and misunderstanding them?
template <class InputIterator, class Type>
InputIterator find(InputIterator first, InputIterator last, const Type& val);
Note that InputIterator here is just a name of a template type parameter, and any const_iterator will satisfy the requirements for it.
Or, perhaps, you're confusing const_iterator (i.e. an iterator referencing a const value) with a const iterator (i.e. an iterator which is itself const)?
std::find and std::find_if both take the iterator type as a template parameter, so they most certainly can operate on const_iterators. Just for a quick example:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> x;
std::fill_n(std::back_inserter(x), 20, 2);
x.push_back(3);
std::vector<int>::const_iterator b = x.begin();
std::vector<int>::const_iterator e = x.end();
std::vector<int>::const_iterator p = std::find(b, e, 3);
std::cout << *p << " found at position: " << std::distance(b, p) << "\n";
return 0;
}
This should be accepted by any properly functioning C++ compiler, and produce results like:
3 found at position: 20
I have just had the same problem. I had a member function that was calling find_if on a member vector, and the compiler gave me an error when I tried making the member function const. It turned out that this was because I was assigning the return value of find_if to an iterator instead of const_iterator. The caused the compiler to assume that the parameters of find_if must also be iterator instead of const_iterator, which it could not get from the const member vector.
If by any chance you are here for the same reason as me:
error: no matching function for call to ‘find(std::vector<int>::const_iterator, std::vector<int>::const_iterator, int)’
It doesn't have anything to do with const_iterators. You probably just forgot to #include <algorithm> :-)
I just had an issue with this code:
std::string str;
std::string::const_iterator start = str.begin();
std::string::const_iterator match = std::find(start, str.end(), 'x');
The error was "no matching overload for std::find".
The fix I needed was to use cend(). It's confusing that cbegin() isn't required, I'm not sure why that conversion is okay (implicitly) and not for the end() as a function parameter.

loop in vector c++ using iterator

I have this code:
std::vector<A>::iterator it;
for(auto it = m_vA.begin(); it != m_vA.end(); it++)
and I gon an error:
ISO C++ forbids declaration of 'it' with no type
cannot convert '__gnu_cxx::__normal_iterator<A* const*, std::vector<tp::Vehicule*, std::allocator<A*> > >' to 'int' in initialization
and If I remove the auto
erreur: no match for 'operator=' in 'it = ((const B*)this)->B::m_vA.std::vector<_Tp, _Alloc>::begin [with _Tp = A*, _Alloc = std::allocator<A*>]()'
B is the class with my loop
Thanks
For auto you seem not to have c++11 enabled, if you enable it, you should remove this line:
std::vector<A>::iterator it;
If you cannot use c++11 and for error after you remove auto, looks like you put this code into const method, so replace iterator with const_iterator:
std::vector<A>::const_iterator it;
for(it = m_vA.begin(); it != m_vA.end(); it++)
You can also make it one line, if you do not need this iterator after the loop:
for(std::vector<A>::const_iterator it = m_vA.begin(); it != m_vA.end(); it++)
From what I see, you are in a const method, you should use const_iterator, or remove the const.
And auto isn't needed if you declare your variable before. It won't produce an error, just a warning, but you've got to choose one way or the other ;)
To solve your problem remove auto keyword.
You must have C++11 enabled to use auto like that. If you are using gcc compiler, you can enable it by -std=c++11 or -std=c++0x compiler's switch.
Currently it's using auto keyword inherited by older C compilers which simply will be omited. Compiler thinks you're declaring it again but without type.
If you do have C++11 enabled, then why are you using auto like this? Simply use a range-based for loop:
for (auto i : m_vA)
// do stuff here with i
Also, the problem with your code is that you specified the type of it, so there's no point in using auto in the for loop. Again, if you're using C++11, you should use the above loop, because it's far easier to write and understand.

Resources