这是一个过于复杂的解决方案。
首先,我们从index 类型开始。它可以存储任何模拟迭代器和/或积分的东西(基本上,支持 + 标量、增量到标量、复制、破坏和相等):
template<class T,
class Category=std::random_access_iterator_tag,
class Delta=decltype(std::declval<T>()-std::declval<T>())
>
struct index:
std::iterator<Category, T, Delta, T*, T>
{
T t;
T operator*()const{ return t; }
index& operator++(){++t; return *this;}
index operator++(int){index tmp = *this; ++t; return tmp;}
index& operator--(){--t; return *this;}
index operator--(int){index tmp = *this; --t; return tmp;}
T operator[](size_t i)const{return t+i;}
friend bool operator<(index const& lhs, index const& rhs) {
return rhs.t-lhs.t>0;
}
friend bool operator>(index const& lhs, index const& rhs) {
return rhs<lhs;
}
friend bool operator<=(index const& lhs, index const& rhs) {
return !(lhs>rhs);
}
friend bool operator>=(index const& lhs, index const& rhs) {
return !(lhs<rhs);
}
friend bool operator==(index const& lhs, index const& rhs) {
return lhs.t==rhs.t;
}
friend bool operator!=(index const& lhs, index const& rhs) {
return lhs.t!=rhs.t;
}
friend Delta operator-(index const& lhs, index const& rhs) {
return lhs.t-rhs.t;
}
friend index& operator+=(index& lhs, Delta rhs) {
lhs.t+=rhs;
return lhs;
}
friend index& operator-=(index& lhs, Delta rhs) {
lhs.t-=rhs;
return lhs;
}
friend index operator+(index idx, Delta scalar) {
idx+=scalar;
return idx;
}
friend index operator+(Delta scalar, index idx) {
idx+=scalar;
return idx;
}
friend index operator-(index idx, Delta scalar) {
idx-=scalar;
return idx;
}
};
其中大部分是不需要的,但我想要完整。请注意,这默认情况下声称是随机访问迭代器,但它存在,因为它的引用类型不是引用。我认为谎言是值得的。
使用index,我们既可以创建一个迭代器-over-integrals,也可以创建一个迭代器-over-iterators。下面是我们如何创建一个迭代器之上的迭代器:
using it_category=typename std::iterator_traits<It>::iterator_category;
template<class It, class Category=it_category<It>>
index<It, Category> meta_iterator( It it ) { return {it}; }
接下来,我们希望能够采用一些迭代器,并在范围内进行迭代。这意味着我们需要一个范围类型:
template<class It>
struct range {
It b, e;
range(It s, It f):b(s),e(f){}
range():b(),e(){}
It begin()const{return b;}
It end()const{return e;}
bool empty()const{return begin()==end();}
template<class R>
range(R&& r):range(std::begin(r),std::end(r)){}
};
这是一个接受可迭代范围(不仅是range,还包括任何容器)并获取迭代器类型的特征。请注意,启用 ADL 的高级功能是个好主意:
template<class R>
using iterator=decltype(std::begin(std::declval<R&>()));
随机助手:
template<class R,class It=iterator<R>>
range<It> make_range(R&&r){ return {std::forward<R>(r)}; }
template<class It
range<It> make_range(It s, It f){return {s,f};}
这是一个有用的助手,可以解决我们的问题:
template<class R>
range<meta_iterator<iterator<R>> iterators_into( R&& r ){
return {meta_iterator(std::begin(r)), meta_iterator(std::end(r))};
}
我们完成了:
std::vector<int> v;
for(auto it: iterators_into(v)) {
}
为v 的每个元素返回一个迭代器。
对于工业质量,您会希望通过 ADL 改进事物。此外,处理输入范围的右值存储可以让您在for(:) 循环中更好地链接范围适配器。