15

I have a function that looks like this:

void myclass::myfunc()
{
    int i;
    for( std::vector<Foo>::iterator it = var.begin(), i = 0; it < var.end(); it++, i++ )
    {
        /* ... */
    }
}

I'm getting this error:

Cannot convert from int to std::_Vector_iterator<>

What is wrong with this code?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Igor
  • 5,620
  • 11
  • 51
  • 103
  • 2
    Use `++it` in order to increment iterator, because `it++` is the post-increment, and takes unnecessary time. – marbel82 Jun 10 '13 at 10:13

4 Answers4

23

The issue is with this part of the for loop:

std::vector<Foo>::iterator it = var.begin(), i = 0

C++ is interpreting this not as two comma-separated statements, but as a variable declaration for a variable named it that's an iterator, and as a new declaration of a variable i that's an iterator and initialized to 0. The error is because you can't initialize a vector iterator to 0.

To fix this, you'll need to hoist the definition outside of the loop:

int i = 0;
std::vector<Foo>::iterator it = var.begin();
for(; it < var.end(); it++, i++ )
{
     // ...
}

Or move the initialization of i outside the loop:

int i = 0;
for( std::vector<Foo>::iterator it = var.begin(); it < var.end(); it++, i++ )
{
    // ...
}

Here's another option. If you need to keep track of the index into the vector you're currently looking at, you could consider just using a counting for loop (without the iterator), or using just the iterator and using iterator subtraction to recover the index:

for (auto it = var.begin(); it != var.end(); ++it) {
    // current position is it - var.begin();
}

And, finally, if you have a C++20-compliant compiler, you could eliminate the iterator entirely and use an enhanced for loop in the following way:

/* Requires C++20 */
for (int i = 0; Foo f: var) {
    /* Do something worthwhile with f. */

    i++;
}

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • I thought that since I already initialized the iterator it will be variable initialization. Guess I was wrong. I will be using the fix #2. Thank you. – Igor Jun 10 '13 at 04:35
13

You can do it like this:

int i = 0;
for( std::vector<int>::iterator it = v.begin(); it < v.end(); ++it, ++i){}
Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
Andrey Tuganov
  • 351
  • 1
  • 8
2

Get rid of the i=0; part (at least inside the loop header).

Also, if you insist on doing this at all, consider using:

for (auto it : var)

or:

for (auto it = var.begin(); it != var.end(); ++it)

...instead. Since you're using a random access iterator anyway, what you have as i is equivalent to it - var.begin(). Conversely, you could just use:

for (int i=0; i<var.size(); i++)

...and get an iterator when needed as var.begin() + i.

Depending on what's in the body of the loop, you probably want to get rid of the loop entirely, and replace it with an algorithm though.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I'd love to use "auto", but I'm afraid that it's not compatible with OS X 10.6 XCode. Also I'm using iterators for efficiency, otherwise I'd definitely use just you 3rd form. Also what do you mean by "get rid of the loop". Could you clarify on how do I go thru the vector? – Igor Jun 10 '13 at 04:32
1

Double iteration:

using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
  /* ... */
}

double iteration with named indexes/iterators:

using std::begin; using std::end;
int i;
std::vector<Foo>::iterator it;
for (std::tie( it, i ) = std::make_pair( begin(var), 0 ); it != end(var); ++it, ++i ) {
  /* ... */
}

or bind the above pair on each iteration to better named variables:

using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
  auto const& it = p.first;
  int i = p.second;
}
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524