На основе диапазона для в C++11

В C++ 11, если у нас есть set<int> S; мы могли бы сказать:

for (auto i: S)
    cout << i << endl;

но можем ли мы заставить i чтобы быть итератором, я имею в виду написать код, который эквивалентен:

for (auto i = S.begin(); i != S.end(); i++)
    cout << (i != s.begin()) ? " " : "" << *i;

или мы могли бы сделать что-то, что мы можем понять индекс i в наборе (или векторе)?

и другой вопрос, как мы можем сказать, что не делайте этого для всех элементов в S но для первой половины или для всех, кроме первой.

или когда у нас есть vector<int> Vи хотите напечатать его первым n ценности что нам делать? Я знаю, что мы можем создать новый вектор, но требуется время, чтобы скопировать вектор в новый вектор.

6 ответов

Решение

Нет, к несчастью. Посмотрите, что говорит стандарт:

Основанный на диапазоне для оператора for ( for-range-объявление: выражение) оператор эквивалентен

{
    auto && __range = ( expression );
    for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}

где __range, __begin и __end - переменные, определенные только для экспозиции

Другими словами, это уже повторяется от begin в end и уже разыменовывает итератор, который вы никогда не увидите.

Принцип дальномерности for это итерация по всему диапазону.

Однако вы сами решаете, что такое диапазон, поэтому вы можете работать с самим диапазоном.

template <typename It>
class RangeView {
public:
  typedef It iterator;

  RangeView(): _begin(), _end() {}
  RangeView(iterator begin, iterator end): _begin(begin), _end(end) {}

  iterator begin() const { return _begin; }
  iterator end() const { return _end; }

private:
  iterator _begin;
  iterator _end;
};

template <typename C>
RangeView<typename C::iterator> rangeView(C& c, size_t begin, size_t end) {
  return RangeView<typename C::iterator>(
           std::next(c.begin(), begin),
           std::next(c.begin(), end)
         );
}

template <typename C>
RangeView<typename C::const_iterator> rangeView(C const& c, size_t begin, size_t end) {
  return RangeView<typename C::const_iterator>(
           std::next(c.begin(), begin),
           std::next(c.begin(), end)
         );
}

Хорошо, это серьезно ресембл Boost.Range...

А теперь давайте использовать это!

for (auto i: rangeView(set, 1, 10)) {
  // iterate through the second to the ninth element
}

В общем случае вам придется использовать отдельную переменную:

int i = 0;

for (auto x : s)
    cout << (i++ ? " " : "") << x << endl;

Есть, конечно, трюки для некоторых контейнеров, таких как vector, но ни один не работает для каждого контейнера.

Вам, вероятно, было бы лучше использовать равнину for петля для этой цели.

Нет, ты не можешь.

for (... : ...)

называется for вместо foreach только по причине не введения нового ключевого слова. Весь смысл foreach быстрый короткий синтаксис для итерации всех элементов без учета их индекса. Для всех других ситуаций просто for что служит своей цели довольно эффективно.

Вы не можете в set, Используйте традиционный for синтаксис или поддерживать свой собственный счетчик индекса.

Вы можете в vector или другой контейнер с плоской компоновкой, такой как std::array или массив в стиле C. Измените его, чтобы использовать ссылку.:

for (auto &i: S)

Тогда вы можете сравнить адрес i с адресом s[0] чтобы получить индекс.

Диапазон на основе for предназначен для простых случаев. Я ожидаю, что он будет немного полезен при создании прототипа чего-либо, но я ожидаю, что его использование в основном прошло задолго до того, как вещи действительно стали продуктом. Возможно, это может быть полезно, чтобы облегчить жизнь новичкам, но об этой области я не могу судить (но то, что, кажется, движет многими недавними обсуждениями C++).

Единственным конструктивным подходом может быть использование адаптера, который ссылается на базовый диапазон и чей begin() а также end() методы корректируют итератор соответствующим образом. Также обратите внимание, что вы, вероятно, хотите поднять любую особую обработку первого или последнего элемента из цикла, обрабатывающего большую часть данных. Конечно, это всего лишь еще одна проверка, за которой следует правильно спрогнозированная ветвь против отсутствия проверки и меньшего загрязнения таблиц прогнозирования ветвлений.

Другие вопросы по тегам