在没有警告(或编译指示)的情况下可移植地"在条件表达式中分配"的好方法?

Meh*_*dad -1 c++ conditional variable-assignment

我有一段这样的代码:

bool finished = false;
size_t offset = 0;
for (Iter i = items.begin();
          i != items.end() || (finished = !finished);
          finished ? i : ++i, ++offset)
{
    do_some_work();
    if (some_condition(other_collection[offset]))
    {
        i = items.insert(i, new_value());
        do_more_work();
        if (blah) { continue; }
    }
    do_more_work();
}
Run Code Online (Sandbox Code Playgroud)

目标是为所有迭代器执行主体,包括end().

我从Visual C++等编译器获得"条件表达式中的赋值"警告.

避免这些警告的最简单方法是什么?

我不想关闭它们(它们很有帮助)而且我不想插入#pragmas(它们在编译器之间不可移植).
我只想写一些简短的东西来告诉典型的编译器,"是的,我打算在这里分配".

我发现的最简单的解决方案是创建一个函数(例如assign)并调用它,但我想知道是否有任何方法也可以避免为此定义一个新函数.

Mar*_*cia 5

使用好的'' for i!

#include <vector>
#include <iostream>


int main() {
    std::vector<int> v = { 1, 5, 23, 2, 44 };
    auto iter = v.begin();
    for (std::size_t i = 0; i != v.size() + 1; ++i, ++iter) {
        if(iter == v.end()) {
            std::cout << "END!" << std::endl;
        }
        else {
            std::cout << *iter << std::endl;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现场代码


更新:为了回应你的评论,我修改了代码使用std::distance,让你只使用迭代器而不直接知道迭代器范围的大小.

#include <vector>
#include <iostream>


template<typename IterType>
void print(IterType iter /* begin */, IterType end) {
    auto size = std::distance(iter, end);
    for (decltype(size) i = 0; i != size + 1; ++i, ++iter) {
        if(iter == end) {
            std::cout << "END!" << std::endl;
        }
        else {
            std::cout << *iter << std::endl;
        }
    }
}


int main() {
    std::vector<int> v = { 1, 5, 23, 2, 44 };
    print(v.begin(), v.end());
}
Run Code Online (Sandbox Code Playgroud)

现场代码

  • 你的循环已经执行了O(n)步骤.(但如果你真的想要反对,请考虑输入迭代器) (4认同)

Yak*_*ont 5

在这种情况下,您不会迭代容器的内容.相反,您正在迭代容器的有效迭代器.

因此,一种方法是明确这一点.

创建一个所述迭代器的序列,其end元素是end序列的最后一个迭代器的一个元素.

因为我疯了,如果我必须解决这个问题,我会编写一个函数iterators,当给定一个sequence(一个for( : )循环工作的对象)时,会生成一个sequence迭代器而不是底层类型的序列.

它需要一个enum论证,说它是否包含了end迭代器.它将默认为独占.

你会这样使用它:

for( auto it : iterators( sequence, include_end ) ) {
  // code
}
Run Code Online (Sandbox Code Playgroud)

编写该函数的工作不会是微不足道的,但它会使得使用点的循环看起来非常干净.

以理智的方式编写它将涉及使用boost迭代器库.稍微不那么理智将涉及重新实现一个boost迭代器库,无论是逐字还是通过手写更糟,然后使用它.在不复制精神或文本的情况下编写它将boost是一个坏主意.

template<typename iterator>
struct iterator_iterator: boost::iterator_facade<
  iterator_iterator<iterator>, iterator,
  typename std::iterator_traits<iterator>::iterator_category,
  iterator const&,
  typename std::iterator_traits<iterator>::difference_type
>:{
  // sufficient state:
  iterator current;
  iterator src_end;
  bool past_end_iterator;
  // now, implement the core operations.  Note that
  // random advance has to be careful, because we cannot advance
  // current beyond src_end.  Note we should implement every one
  // of the methods in the requirements (including advance), but
  // only the ones that the underlying iterator's category requires
  // should be called and hence instantiated.
  iterator dereference() const { return current; }
  bool equal( iterator_iterator<iterator> other ) const {
    if (past_end_iterator || other.past_end_iterator)
      return past_end_iterator && other.past_end_iterator;
    return current == other.current;
  }
  void increment() {
    if (current == src_end) {
      past_end_iterator = true;
    } else {
      ++current;
    }
  }
  void decrement() {
    if (past_end_iterator) {
      past_end_iterator = false;
    } else {
      --current;
    }
  }
  void advance( std::ptrdiff_t n ) {
    if (n==0)
      return;
    if (n==1) {
      increment();
    } else if (n==-1) {
      decrement();
    }
    if ((n>0) && ( current+(n-1) == src_end ) {
      current = src_end;
      past_end_iterator = true;
    } else if ((n<0) && past_end_iterator) {
      past_end_iterator = false;
      ++n;
      current = src_end + n;
    } else {
      current += n;
    }
  }
  typename std::iterator_traits<iterator>::difference_type distance_to(
    iterator_iterator<iterator> other
  ) const {
    if (past_end_iterator || other.past_end_iterator) {
      if (past_end_iterator && other.past_end_iterator) {
        return 0;
      using std::distance;
      auto retval = distance( current, other.current );
      if (past_end_iterator)
        return retval-1;
      else
        return retval+1;
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

或类似的东西.(编译没有,只是写的)你最好把你对开始/结束迭代器,以及创建一对开始/结束迭代器迭代器,或者开始/结束过去迭代器迭代器,这取决于您是否要包括结束迭代在迭代器的迭代中.

我怀疑上面的CRTP是堆栈溢出代码中迭代器一词有用的最高密度:在5行代码中使用迭代器.