Ответ 1
Да, но вместо этого я использовал бы vec.data()
. Бонус использования .data()
заключается в том, что у небезупречных контейнеров std
его нет, поэтому ваш код надежно прекращает компиляцию, когда переименованный контейнер не работает таким образом (например, deque
или 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
по мере необходимости при создании индексов и диапазонов. Поддержка Sentinals на диапазонах. Сделайте range_t
интерфейс более богатым (size
, необязательный произвольный доступ []
, empty
, front
, back
, range_t range_t::without_front(n) const
и т.д.