代码之家  ›  专栏  ›  技术社区  ›  Peter

如何在循环中用增量构造std::list迭代器

  •  7
  • Peter  · 技术社区  · 15 年前

    我尝试在std::list上做一个双循环,以便对每对元素进行操作。但是,我在初始化第二个迭代器时遇到一些问题。我想写的代码是:

    for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
        for(std::list<int>::iterator j = i+1; j != l.end(); ++j) {
            ...
        }
    }
    

    这不起作用,因为列表迭代器不是随机访问,所以不能执行+1。但是我很难找到一个完美的替代方案;编译器似乎对 std::list<int>::iterator j(i)++; 我有一些希望。实现我想要的,似乎我必须有一些笨拙的额外增量,这将无法很好地适应for循环的结构。

    有明显的替代方法(例如,使用向量!)但在我看来,应该有一些相当整洁的方式来做这件事,我只是暂时看不到。

    感谢您的帮助:)

    7 回复  |  直到 15 年前
        1
  •  8
  •   Sean    15 年前

    怎么样:

    for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
        for (std::list<int>::iterator j = i; ++j != l.end(); ) {
            // ...
        }
    }
    
        2
  •  9
  •   dirkgently    15 年前
    for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
        std::list<int>::iterator j = i;
        for(std::advance(j, 1); j != l.end(); ++j) {
            ...
        }
    }
    
        3
  •  4
  •   ebo    15 年前
    for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
        std::list<int>::iterator j = i; ++j;
        for(; j != l.end(); ++j) {
            ...
        }
    }
    

    回到游戏中!

    实际上,这是数字算法中一个很常见的习语,所以我不认为它是丑陋的。

        4
  •  2
  •   GManNickG    15 年前

    我只是放弃了我在德克格尼蒂的回答中的想法:

    template <typename Iter, typename Dist>
    Iter advance_copy(Iter pIter, const Dist& pOffset)
    {
        std::advance(pIter, pOffset);
    
        return pIter;
    }
    
    // ...
    
    typedef std::list<int> int_list;
    
    for(int_list::iterator i = l.begin(); i != l.end(); ++i)
    {
        for(int_list::iterator j = advance_copy(i, 1); j != l.end(); ++j)
        {
        }
    }
    

    您也可以制作另一类实用程序函数,以使其简洁:

    // for consistency,
    template <typename Iter>
    void increment(Iter& pIter)
    {
        ++pIter;
    }
    
    template <typename Iter>
    Iter increment_copy(Iter pIter)
    {
        return ++pIter;
    }
    
    // ...
    
    typedef std::list<int> int_list;
    
    for(int_list::iterator i = l.begin(); i != l.end(); ++i)
    {
        for(int_list::iterator j = increment_copy(i); j != l.end(); ++j)
        {
        }
    }
    
        5
  •  2
  •   AnT stands with Russia    15 年前

    简单的“整洁”选项可以基于这样一个事实:列表迭代器是一个用户定义类型的对象,带有重载的运算符(而不是内置类型)。(当然,这并没有得到正式的保证,但是可以根据列表容器的性质来期望。)因此,可以应用重载的前缀。 ++ 运算符到列表迭代器类型的临时对象。

    为了实现你想要的,你只需要创建一个 i ,使用前缀递增 ++ 然后使用结果值初始化 j

    for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
      for(std::list<int>::iterator j = ++std::list<int>::iterator(i); j != l.end(); ++j) { 
        ... 
      } 
    } 
    

    就是这样。注意,这个技巧相当流行,可以在实时代码中不时遇到。还要注意的是,它通常不适用于 std::vector 因为许多实现使用普通的内置指针作为向量迭代器,但是它通常可以与 std::list .

    但是,就个人而言,我不会在代码中真正使用它。您已经收到了几个很好的答案,可以通过添加一行代码来实现这一点。

        6
  •  1
  •   anon    15 年前

    我赞成肖恩的建议,只是先做个循环:

    for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
        std::list<int>::iterator j( i ); 
        while( ++j != l.end() ) {
            // ...
        }
    }
    
        7
  •  0
  •   avakar    15 年前

    如果你已经在使用Boost,那么最简单的方法就是使用 boost::next .

    for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i)
        for(std::list<int>::iterator j = boost::next(i); j != l.end(); ++j)