Сокращение for-loop - синтаксический сахар в С++ (11)
На самом деле это два связанных вопроса.
Я знаю, что в С++ 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]){ ... }
было бы здорово.
Для обоих вопросов я хотел бы избежать использования дополнительных библиотек.
Ответы
Ответ 1
Первый ответ: вы этого не делаете. Вы использовали простую конструкцию для простой цели; вам понадобится нечто более сложное, если у вас есть более сложные потребности.
Второй ответ: вы можете создать тип итератора, который дает последовательные целочисленные значения, и тип "контейнер", который дает ряд из них. Если у вас нет веских оснований для этого, Boost имеет такую вещь:
#include <boost/range/irange.hpp>
for (int i : boost::irange(0,100)) {
// i goes from 0 to 99 inclusive
}
Ответ 2
Используйте это:
size_t pos = 0;
for (auto& i : v) {
i = pos;
++pos;
}
(Boost хорош, но он не универсально принят.)
Ответ 3
Для первого вопроса ответ довольно прост: если вам нужен счетчик итераций, не используйте синтаксическую конструкцию, которая абстрагирует счетчик итераций. Просто используйте обычный цикл for
, а не диапазон.
Во втором вопросе я не думаю, что в стандартной библиотеке ничего нет, но вы можете использовать boost::irange
для него:
for (int i : boost::irange(0, 100))
Ответ 4
Для второго вопроса - если 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 и только для заголовков.
Ответ 5
Вы можете сделать обе эти вещи с помощью 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
Ответ 6
Если 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>::reference
для элементов.
Здесь находится итератор Boost zip: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html - есть ли диапазон расширений Boost, который обрабатывает синтаксис, как указано выше zip
функция.
Ответ 7
Для второго вопроса:
Есть другой способ, но я бы не использовал или не рекомендовал его. Однако для быстрой настройки теста вы можете написать:
если вы не хотите использовать библиотеку, и вы в порядке, только предоставляя верхнюю границу диапазона, который вы можете написать:
for (auto i:vector<bool>(10)) {
cout << "x";
}
Это создаст логический вектор размера 10 с неинициализированными значениями. Перейдя через эти униализированные значения с помощью i
(поэтому не используйте i
), он будет печатать 10 раз "x".
Ответ 8
Во втором вопросе, если вы используете новейшие версии Visual Studio, введите "if", затем Tab, Tab и Tab, чтобы заполнить значение инициализации, повышение и т.д.