it-swarm.com.ru

Сокращение для цикла for - синтаксический сахар в C++ (11)

На самом деле это два взаимосвязанных вопроса.

Я знаю, что в C++ 11 есть новый синтаксис для циклических for циклов вида:

//v is some container
for (auto &i: v){
   // Do something with i
}

Первый вопрос: как я могу определить, на какой итерации я нахожусь в этом цикле? (Скажем, я хочу заполнить вектор значением j в позиции j).

Второй вопрос: я хотел знать, есть ли какой-то другой способ написать цикл в форме

for (int i=0; i<100; i++) { ... }

Я нахожу этот способ написания немного громоздким, и я делаю это так часто, и я хотел бы иметь более сжатый синтаксис для него .... Что-то вроде:

for(i in [0..99]){ ... }

было бы замечательно.

Для обоих вопросов я бы хотел избежать использования дополнительных библиотек.

13
dingalapadum

Первый ответ: нет. Вы использовали простую конструкцию для простой цели; вам нужно что-то более сложное, если у вас есть более сложные потребности.

Второй ответ: вы можете создать тип итератора, который выдает последовательные целочисленные значения, и тип «контейнер», который задает диапазон из них. Если у вас нет веской причины сделать это самостоятельно, у Boost есть такая вещь :

#include <boost/range/irange.hpp>

for (int i : boost::irange(0,100)) {
    // i goes from 0 to 99 inclusive
}
20
Mike Seymour

Использовать этот:

size_t pos = 0;
for (auto& i : v) {
    i = pos;
    ++pos;
}

( Повышение это хорошо, но это не является общепринятым.)

14
Peter K

На первый вопрос ответ довольно прост: если вам нужен счетчик итераций, не используйте синтаксическую конструкцию, которая абстрагирует счетчик итераций. Просто используйте обычный цикл for, а не диапазон.

Что касается второго вопроса, я не думаю, что в стандартной библиотеке в настоящее время есть что-то, но вы можете использовать для него boost::irange :

for (int i : boost::irange(0, 100))
10
Angew

Для второго вопроса - если Boost слишком тяжелый, вы всегда можете использовать эту библиотеку:

for(auto i : range(10, 15)) { cout << i << '\n'; } напечатает 10 11 12 13 14

for(auto i : range(20, 30, 2)) { cout << i << '\n'; } напечатает 20 22 24 26 28

Также поддерживаются двойные и другие числовые типы.

Он имеет другие инструменты итерации Pythonic и только для заголовка.

4
onqtam

Вы можете сделать обе эти вещи с Boost.Range: http://boost.org/libs/range

Для краткости (и чтобы немного оживить ситуацию, так как boost::irange уже был продемонстрирован отдельно), вот пример кода, демонстрирующий совместную работу этих функций:

// boost::adaptors::indexed
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
#include <boost/range/adaptor/indexed.hpp>

// boost::irange
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html
#include <boost/range/irange.hpp>

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> input{11, 22, 33, 44, 55};
    std::cout << "boost::adaptors::indexed" << '\n';
    for (const auto & element : input | boost::adaptors::indexed())
    {
        std::cout << "Value = " << element.value()
                  << " Index = " << element.index()
                  << '\n';
    }

    endl(std::cout);

    std::cout << "boost::irange" << '\n';
    for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100))
    {
        std::cout << "Value = " << element.value()
                  << " Index = " << element.index()
                  << '\n';
    }

    return 0;
}

Образец вывода:

boost::adaptors::indexed
Value = 11 Index = 0
Value = 22 Index = 1
Value = 33 Index = 2
Value = 44 Index = 3
Value = 55 Index = 4

boost::irange
Value = 0 Index = 100
Value = 1 Index = 101
Value = 2 Index = 102
Value = 3 Index = 103
Value = 4 Index = 104
3
Matt

Если v является вектором (или любым std непрерывным контейнером), то

for(auto& x : v ) {
  size_t i = &x-v.data();
  x = i;
}

установит для i-й записи значение i.

Подсчитываемый выходной итератор достаточно прост для написания. Boost имеет один и имеет легкий для генерации диапазон их, называемый irange.

Извлечение индексов контейнера является относительно простым. Я написал функцию с именем indexes, которая может принимать контейнер или диапазон целых чисел и генерировать случайные выходные итераторы по рассматриваемому диапазону.

Это дает вам:

for (size_t i : indexes(v) ) {
  v[i] = i;
}

Вероятно, в Boost есть эквивалентная функция диапазона от контейнера к индексу.

Если вам нужны оба, и вы не хотите делать работу, вы можете написать молнию.

for( auto z : Zip( v, indexes(v) ) ) {
  auto& x = std::get<0>(z);
  size_t i = std::get<1>(z);
  x = i;
}

где Zip принимает два или более итерируемых диапазона (или контейнера) и создает представление диапазона по кортежам iterator_traits<It>::references для элементов.

Вот итератор Boost Zip: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/Zip_iterator.html - есть вероятность, что существует диапазон Boost Zip, который обрабатывает синтаксис, такой как выше Zip функция.

1
Yakk - Adam Nevraumont

Для 2-го вопроса:

Есть другой способ, но я бы не использовал или не рекомендовал его . Однако для быстрой настройки теста вы можете написать:

если вы не хотите использовать библиотеку, и вы можете указать только верхнюю границу диапазона, который вы можете написать:

for (auto i:vector<bool>(10)) {
    cout << "x";
}

Это создаст логический вектор размера 10 с неинициализированными значениями. Перебирая эти унифицированные значения с помощью i (так что not используйте i), он напечатает 10 раз «x».

1
Stuck

Для второго вопроса, если вы используете последние версии Visual Studio, введите "если", то TabTab, а также Tab заполнить начальное значение, повышение и так далее.

0
Sheen