Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use += operator on a list iterator?

I have a iterator from a std::list<std::string>, but when I attempt to advance it using +=, I get a compilation error.

The code is:

#include <list>
#include <iostream>
#include <string>
int main() {
    std::list<std::string> x;

    x.push_front("British");
    x.push_back("character");
    x.push_front("Coding is unco");
    x.push_back("Society");
    x.push_back("City Hole");
    auto iter = x.begin();
    iter += 3;
    //std::advance(iter, 3);
    x.erase(iter);

    for (auto &e: x) {
        std::cout << e << "\n";
    }
}

If I compile this using clang++ -std=c++11 -o li li.cpp, I get:

li.cpp:13:10: error: no viable overloaded '+='
    iter += 3;
    ~~~~ ^  ~
1 error generated.

Why can't I use += with this iterator?

like image 431
KiYugadgeter Avatar asked Nov 29 '22 06:11

KiYugadgeter


2 Answers

The reason is simply that the += operator is not defined for the Bidirectional iterator you are using.

For all iterators there is at least:

  • Copy-assignable and destructible, i.e. X b(a); and b = a;
  • Can be incremented, i.e. ++a and a++

Everything else depends on the type of iterator check the table here:

enter image description here

As you see a random-access iterator would do the trick.

like image 36
Beginner Avatar answered Nov 30 '22 20:11

Beginner


The iterator for std::list is BidirectionalIterator, which doesn't support operator+= like RandomAccessIterator.

You can use operator++, which is supported by InputIterator (including BidirectionalIterator), something like

++iter;
++iter;
++iter;

But it's ugly. The best way is as you commented, to use std::advance (or std::next (since C++11)) instead, which could be used with InputIterator (including BidirectionalIterator), and also takes advantage of the features supported by RandomAccessIterator.

(emphasis mine)

Complexity

Linear.

However, if InputIt additionally meets the requirements of RandomAccessIterator, complexity is constant.

So you can just use it without considering about the category of the iterator, std::advance will do the best choice for you. e.g.

std::advance(iter, 3);

or

iter = std::next(iter, 3);
like image 156
songyuanyao Avatar answered Nov 30 '22 19:11

songyuanyao