user788171
user788171

Reputation: 17553

C++ comparing iterator with int

Is there a simple way to compare an iterator with an int?

I have a loop like this:

for (std::vector<mystruct>::const_iterator it = vec->begin(); it != vec->end(); ++it)

Instead of looping over the entire vector, I would like to just loop over the first 3 elements. However, the following does not compile:

for (std::vector<mystruct>::const_iterator it = vec->begin(); it < 3; ++it)

It there a good way to achieve the same effect?

Upvotes: 2

Views: 3474

Answers (4)

xaviersjs
xaviersjs

Reputation: 1737

Sure, you can simply go three elements past the beginning.

for (std::vector<mystruct>::const_iterator it = vec->cbegin(); it != vec->cbegin() + 3; ++it)

However, that might be error prone since you might try to access beyond the end in the case that the vector is fewer than 3 elements. I think you'd get an exception when that happens but you could prevent it by:

for(std::vector<mystruct>::const_iterator it = vec->cbegin(); it != vec->cend() && it != vec->cbegin() + 3; ++it)

Note the use of cbegin() and cend() since you asked for a const_iterator, although these are only available in c++11. You could just as easily use begin() and end() with your const_iterator.

Upvotes: 0

Angel Koh
Angel Koh

Reputation: 13505

since it's a vector, why not just access its position directly ?

if (vec->size() > 0)
{
    for (int i =0; i<3 && i< vec->size(); i++)
    {
        // vec[i] can be accessed directly
        //do stuff 
    } 
}

Upvotes: 4

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

I'd want to be careful, because you can easily run into fencepost bugs.

This works on random access containers (like vector and array), but doesn't do ADL on begin because I'm lazy:

template<typename Container>
auto nth_element( Container&& c, std::size_t n )->decltype( std::begin(c) )
{
  auto retval = std::begin(c);
  std::size_t size = std::end(c) - retval;
  retval += std::min( size, n );
  return retval;
}

It returns std::end(c) if n is too big.

So you get:

for( auto it = vec->cbegin(); it != nth_element(vec, 3); ++it) {
   // code
}

which deals with vectors whose size is less than 3 gracefully.

The basic core of this is that on random access iterators, the difference of iterators is ptrdiff_t -- an integral type -- and you can add integral types to iterators to move around. I just threw in a helper function, because you should only do non-trivial pointer arithmetic (and arithmetic on iterators is pointer arithmetic) in isolated functions if you can help it.

Supporting non-random access iterators is a matter of doing some traits checks. I wouldn't worry about that unless you really need it.

Note that this answer depends on some C++11 features, but no obscure ones. You'll need to #include <iterator> for std::begin and std::end and maybe <algorithm> for std::min.

Upvotes: 3

Pubby
Pubby

Reputation: 53047

std::next(vec->begin(), 3); will be the the iterator 3 places after the first, and so you can compare to it:

for (std::vector<mystruct>::const_iterator it = vec->begin(); it != std::next(vec->begin(), 3); ++it)

Your vector will need to have at least 3 elements inside it though.

Upvotes: 4

Related Questions