我有一段这样的代码:
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();
}
目标是执行所有迭代器的主体,包括end()
。
我得到了";条件表达式中的赋值";来自Visual C++等编译器的警告。
避免这些警告的最简单方法是什么
我不想关闭它们(它们很有用),也不想插入#pragma
(它们在编译器之间不可移植)
我只想写一些简短的东西,告诉典型的编译器,";是的,我打算在这里分配";。
我发现的最简单的解决方案是创建一个函数(例如assign
)并调用它,但我想知道是否有任何方法可以避免为此定义新函数。
使用好的ol‘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;
}
}
}
实时代码
更新:为了回应您的评论,我修改了代码,改为使用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());
}
实时代码
在这种情况下,您不会迭代容器的内容。相反,您正在对容器的有效迭代器进行迭代。
因此,一种方法是明确这一点。
创建一个所述迭代器的序列,其中end
元素是该序列最后一个迭代器之后的end
元素的一个。
因为我疯了,如果必须解决这个问题,我会写一个函数iterators
,当给定sequence
(for( : )
循环处理的对象)时,它会产生迭代器的sequence
,而不是底层类型的序列。
它需要一个enum
参数来说明它是否包含-end
迭代器。它将默认为独占。
你会这样使用它:
for( auto it : iterators( sequence, include_end ) ) {
// code
}
编写该函数的工作并不琐碎,但它会使使用点的循环看起来非常干净。
以合理的方式编写这篇文章需要使用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;
}
}
};
或者类似的东西。(不是编译的,只是编写的)您可以使用一对开始/结束迭代器,然后创建一对开始-结束迭代机,或者创建一个开始-过去-结束迭代器,这取决于您是否希望在迭代器的迭代中包括结束迭代程序。
我怀疑上面的CRTP是堆栈溢出代码中使用迭代器的密度最高的单词之一:在5行代码中使用了13次迭代器。
如果要执行end
的循环,即使它等于begin
,循环也总是至少执行一次。
在这种情况下,将其编写为do
/while
循环可能最简单,因此它只在执行循环体之后测试条件:
bool continuing;
i = begin;
do {
whatever();
} while ((continuing = (i != end)) && (++i, continuing));
丑陋的终止条件针对end测试迭代器的当前值,然后在需要执行另一次迭代的情况下(并且仅在需要执行)为下一次迭代增加迭代器(然后使用原始比较的值来继续/中断循环)。
在Visual Studio 2010(C++)中有一些关于这个问题的讨论:暂时抑制C4706警告
您可以尝试使用!!
来提示您打算将(finished = !finished)
视为布尔值(它是两个按顺序排列的!
一元,并将0转换为0,将其他所有内容转换为1):
bool finished = false;
for (Iterator i = begin; i != end || !! (finished = !finished) ; finished ? i : ++i)
{
// (body)
}
没关系,我自己找到了解决方案。。。
for (Iter i = items.begin();
i != items.end() || (finished = !finished, finished);
finished ? i : ++i, ++offset)
{
// ...
}