为什么我不能在列表迭代器上使用+=运算符?

4
我有一个来自于 std::list<std::string> 的迭代器,但是当我尝试使用 += 来移动它时,编译出错了。
代码如下:
#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";
    }
}

如果我使用 clang++ -std=c++11 -o li li.cpp 进行编译,结果如下:
li.cpp:13:10: error: no viable overloaded '+='
    iter += 3;
    ~~~~ ^  ~
1 error generated.

为什么我不能使用这个迭代器的 += 操作符?

@EdChum 更准确地说,你不能这样增加列表迭代器。 (+ Op 知道 advance,它在评论中) - Borgleader
iter += 3 的意思是 iter = iter + 3,这是不可行的。 - Mudi
只要错误信息相当清晰,我就不太明白问题是什么。 - 463035818_is_not_a_number
@Mudi -- 不是的。iter += 3 的意思是“调用重载运算符 +=”。与数值类型不同,它与 + 没有固有的联系。 - Pete Becker
@PeteBecker 同意! - Mudi
3个回答

17

std::list 的迭代器是 BidirectionalIterator,不支持像 RandomAccessIterator 那样的 operator+=

您可以使用 operator++,它被InputIterator(包括BidirectionalIterator)支持,例如:

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

但这很丑陋。最好的方法是像您评论的那样使用std::advance(或者C++11以后的std::next),它可以与InputIterator(包括BidirectionalIterator)一起使用,并且还利用了RandomAccessIterator支持的特性。

(强调我的)

复杂度

线性。

然而,如果InputIt还满足RandomAccessIterator的要求,则复杂度为常数

因此,您可以直接使用它,无需考虑迭代器的类别,std::advance会为您做出最佳选择。例如:

std::advance(iter, 3);
iter = std::next(iter, 3);

3
OP已经在他们的代码中将此部分注释掉,因此对advance的使用已经是已知的,所以您不需要包括这一部分。 - EdChum
5
@EdChum,这可能对下一个查看该问题的人有所帮助。 - Beginner
@EdChum,我添加了一些关于std::advance的解释。从问题(关于迭代器类别)来看,我认为OP可能还不够理解它。 - songyuanyao
好的,说实话当我第一次评论这个问题时,我错过了这个细节,所以值得强调。 - EdChum

6
原因很简单,您正在使用的双向迭代器未定义+=运算符。对于所有迭代器,至少具备以下功能:
  • 可复制和可销毁,即 X b(a);b = a;
  • 可以递增,即 ++aa++
其他所有功能都取决于迭代器类型,请查看表格here

enter image description here

如您所见,随机访问迭代器可以解决问题。


3
一个 std::list::iterator 不是一个 随机访问迭代器。在链表中不可能“快速跳过”多个元素,必须遍历整个链表直到找到目标元素。你可以使用 std::advance 来推断基于迭代器类别的最佳迭代方式。对于一个 std::list::iterator,它将在循环中递增迭代器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接