对于使用STL函数遍历C数组,std::begin
和std::end
函数非常方便地等同于.begin()
和.end()
。但是,双向C ++容器的反向迭代器没有std::rbegin
和std::rend
等价物。这样的等价物是否存在于其他名称之下,或者是否易于制作?我意识到一个难点是std::begin
通常返回一个原始指针,而对于相反的情况,这需要一个包装器,以便++操作可以重载。一个非常不完整的实现可能看起来像
template<class T>
class ReverseArrayIterator {
public:
ReverseArrayIterator(T* ptr) : _ptr(ptr) {}
operator T*() {
return _ptr;
}
void operator++() {
--_ptr;
}
T operator*() {
return *_ptr;
}
bool operator!= (ReverseArrayIterator& rhs) {
return _ptr != rhs._ptr;
}
private:
T* _ptr;
};
template<class T, size_t size>
ReverseArrayIterator<T> rbegin(T (&array)[size]) {
return ReverseArrayIterator<T>(&array[0] + size - 1);
}
template<class T, size_t size>
ReverseArrayIterator<T> rend(T (&array)[size]) {
return ReverseArrayIterator<T>(&array[0] - 1);
}
我使用以下代码测试了这个简单的实现:
int x[] = {1,2,3,4,5,6,0,0,0,10,11,12};
auto a = std::find(std::begin(x),std::end(x),0);
auto b = std::find(rbegin(x),rend(x),0);
cout << std::distance(x,a) << endl;
cout << std::distance(x,(int*)b) << endl;
这可以充实为C阵列的完全可操作的反向迭代器类,还是会遇到进一步的障碍?一个可能的障碍似乎是隐式转换为原始指针,我希望它可以用在像std :: distance这样的函数中 - 上面的代码片段不会用std::distance(x,b)
编译(或类似函数) ,据推测)但需要手册(int*)
演员。
答案 0 :(得分:2)
(我正在将评论变成帮助他人的答案。感谢chris和StoryTeller。)
自C++14起,rbegin()和rend()就像您所描述的一样。
还有一个adapter class可以将(正向)迭代器转换为反向迭代器。请注意,应将 forward begin()
迭代器传递给make_reverse_iterator
以使 reverse 迭代器生效,反之亦然:
std::vector<int> v{ 1, 3, 10, 8, 22 };
std::copy(
std::make_reverse_iterator(v.end()),
std::make_reverse_iterator(v.begin()),
std::ostream_iterator<int>(std::cout, ", "));
答案 1 :(得分:1)
使用span来包装数组,而不必费心手动滚动建议的代码。
跨度是轻量级的包装程序,用于内存中连续的值序列,为您提供标准库容器在这些值上的所有“便利设施”,包括反向迭代器,循环范围等。
跨度已进入C ++ 20的标准,但是您询问了C ++ 11,因此可以使用C ++准则支持库的跨度,例如来自GSL-lite implementation的版本,该版本支持C ++ 11(Microsoft的GSL不支持)。
跨度是引用类型,并且非常轻巧-经常会被优化掉。因此,使用跨度通常不会花费您任何费用。
在您的示例中,可以使用跨度重写代码,如下所示:
#include <iterator>
#include <gsl/gsl-lite.hpp>
#include <iostream>
int main()
{
int raw_x[] = {1, 2, 3, 4, 5, 6, 0, 0, 0, 10, 11, 12};
auto x = gsl::span<int>{raw_x};
auto a = std::find(x.begin(), x.end(),0);
auto b = std::find(x.rbegin(), x.rend(),0);
std::cout << std::distance(x.begin(), a) << std::endl;
std::cout << std::distance(x.rend(), b) << std::endl;
}
和这个compiles(GodBolt)。
请注意,我使用的是rbegin()
和rend()
成员,而不是std::rbegin()
和std::rend()
,因为后者尚未在C ++ 11中标准化。