是的,但我会vec.data()
改用。使用的一个好处.data()
是非连续std
容器没有它,因此当被迭代的容器不能以这种方式工作时(如deque
or std::vector<bool>
),您的代码可靠地停止编译。(还有其他一些小优点,比如std::addressof
问题,以及它在空容器上定义明确的事实,但这些并不那么重要,尤其是在这里。)
或者,我们编写一个index_t
类似迭代器的包装器:
template<class T>
struct index_t {
T t;
T operator*()const{ return t; }
void operator++() { ++t; }
friend bool operator==( index_t const& lhs, index_t const& rhs ) {
return lhs.t == rhs.t;
}
friend bool operator!=( index_t const& lhs, index_t const& rhs ) {
return lhs.t != rhs.t;
}
};
template<class T>
index_t<T> index(T t) { return {t}; }
index_t<int>
可用于创建计数for(:)
循环。
index_t<iterator>
可用于创建迭代器返回for(:)
循环。
template<class It>
struct range_t {
It b,e;
It begin() const {return b;}
It end() const {return e;}
};
template<class It>
range_t<It> range( It s, It f ) { return {s,f}; }
template<class T>
range_t<index_t<T>>
index_over( T s, T f ) {
return {{{s}}, {{f}}};
}
template<class Container>
auto iterators_of( Container& c ) {
using std::begin; using std::end;
return index_over( begin(c), end(c) );
}
我们现在可以迭代容器的迭代器。
for (auto it : iterators_of(vec))
活生生的例子。
提到的迭代整数是:
for (int i : index_over( 0, 100 ) )
我们也可以直接获取容器的索引:
template<class Container>
range_t< index_t<std::size_t> >
indexes_of( Container& c ) {
return index_over( std::size_t(0), c.size() );
}
template<class T, std::size_t N>
range_t< index_t<std::size_t> >
indexes_of( T(&)[N] ) {
return index_over( std::size_t(0), N );
}
这让我们:
for( auto i : indexes_of( vec ) )
其中i
从0
到不等vec.size()-1
。我发现这有时比 zip 迭代器等更容易使用。
省略的改进:
做index_t
一个真正的input_iterator
. 在制作索引和范围时使用std::move
和/或根据需要。std::forward
支持范围内的哨兵。使range_t
界面更丰富(,可选size
随机访问,,,,,等。[]
empty
front
back
range_t range_t::without_front(n) const