c++ - C++11 - C++条件单向迭代器

我想实现下面的伪代码:


string foo; // or vector<int> foo;


auto itr = bar? foo.begin() : foo.rbegin();


auto end = bar? foo.end() : foo.rend();


for ( ; itr != end; ++itr) {


// SomeAction ...


}



也就是说,我希望将itr设置为前向迭代器或反向迭代器,取决于某些条件bar

显然,这样的代码将无法工作,因为前向迭代器和反向迭代器有不同的类型。

注意,我不想拆分成两个循环,像//SomeAction这样的代码会被复制。

我怎样才能做到这一点?使用C++11和或以前的答案优先。

此外,请详细说明字符串和向量是否有不同的解决方案。

时间:

我将逻辑放在两个迭代器函数中:


<template typename Iter>


void do_stuff(Iter first, Iter last)


{


 for(; first != last; ++first)


 {


 // Do logic


 }


}



bar ? do_stuff(foo.begin(), foo.end()) : do_stuff(foo.rbegin(), foo.rend());



如果不是所有容器,前向和反向迭代器都是不同的类型,因此不能简单地分配给同一变量。

一个选项是将它们的用法移动到模板函数中:


template<class Iterator> void loop(Iterator begin, Iterator end)


{


 for (auto itr = begin; itr != end; ++itr) { ... }


}



if (bar) loop(foo.begin(), foo.end());


else loop(foo.rbegin(), foo.rend());



在较新版本的C++(C ++14和更新,所以,不是C++11中循环函数可以是lambda使用<代码>自动</代码>作为参数类型。


auto loop = [](auto begin, auto end)


{


 for (auto itr = begin; itr != end; ++itr) { ... }


};



另一种选择是使包装器类型可以包含迭代器或反向迭代器,并且与迭代器本身一样。

我不想拆分成两个循环,像//SomeAction这样的代码会被复制。

将动作放入一个lambda 。


auto lambda = [&](char &val) // `ElementType &`


{


 // ...


};



if (bar)


{


 for (auto &val : foo)


 lambda(val);


}


else


{


 for (auto it = foo.rbegin(); it != foo.rend(); it++)


 lambda(*it);


}



另外,使用索引而不是迭代器,这只适用于允许随机访问的容器。


std::size_t i, end, step;


if (bar)


{


 i = 0;


 end = foo.size();


 step = 1;


}


else


{


 i = foo.size() - 1;


 end = -1;


 step = -1;


}



for (; i != end; i += step)


{


 // ...


}



一个选项是为循环编写一个函数模板,该循环适用于任何迭代器,然后有条件地调用模板的一个实例或另一个实例,其他的答案已经展示了如何做的例子。

另外,根据你所做的操作,<algorithm>头中的循环模板可能已经存在,您可以使用(但是,不限于)std :: for_each,std :: accumulate或std :: remove,例如:


auto body = [captures,needed,by,some,action](char c) {


 // SomeAction ...


};


if (bar)


 std::for_each(foo.begin(), foo.end(), body);


else


 std::for_each(foo.rbegin(), foo.rend(), body);



另一种选择是使用类型清除迭代器适配器,它有一个小的运行时开销,在这里可能不需要,但是,如果有一个密切相关的问题,那就更有用了。

从本质上说,这种适配器是模板迭代器什么std::function是模板化的函子参数,它消除了模板的需要,对于抽象接口来说,这是非常有用的,然而,标准库并没有提供这样的迭代器适配器。

迭代器适配器的替代品是范围适配器(也不在标准库中):


using t_erase = boost::adaptors::type_erased<>;


auto range = bar


 ? boost::make_iterator_range(foo.begin(), foo.end()) | t_erase()


 : boost::make_iterator_range(foo.rbegin(), foo.rend()) | t_erase();


for(char c : range) {


 // SomeAction ...


}



...