Лучший способ перебрать целый ряд целых чисел?
Поскольку в C++11 введен цикл for, основанный на диапазоне (на основе диапазона в C++11), каков наилучший способ выражения цикла для целого ряда?
Вместо
for (int i=0; i<n; ++i)
Я хотел бы написать что-то вроде
for (int i : range(0,n))
Поддерживает ли новый стандарт что-либо подобное?
Обновление: эта статья описывает, как реализовать генератор диапазона в C++11: Генератор в C++
6 ответов
Хотя вы не можете сделать это с чистым C++ (с текущими возможностями стандартной библиотеки C++), вы можете сделать это с помощью boost:
#include <boost/range/irange.hpp>
#include <iostream>
using namespace boost;
using namespace std;
int main(int argc, char **argv)
{
for(auto i : irange(1, 10))
cout << i << "\n";
return 0;
}
более того, Boost.Range
содержит еще несколько интересных диапазонов, которые вы можете найти довольно полезными при использовании с новым for
петля. Например, с Boost.Range вы можете сделать обратное for
петля.
С C++20
у нас будут диапазоны. Вы можете попробовать их, загрузив последний стабильный выпуск от его автора, Эрика Ниблера, с его гитхаба или зайдя в Wandbox. Вас интересуетranges::views::iota
, что делает этот код законным:
#include <range/v3/all.hpp>
#include <iostream>
int main() {
using namespace ranges;
for (int i : views::iota(1, 10)) {
std::cout << i << ' ';
}
}
В этом подходе замечательно то, что view
s являются ленивыми. Это означает, что даже еслиviews::iota
представляет собой диапазон от 1
к 10
эксклюзив, не более одного int
из этого диапазона существует в одной точке. Элементы создаются по запросу.
Лучший способ до сих пор это:
for (int i=0; i<n; ++i)
Я думаю, вы можете сделать это, но я бы не назвал это так аккуратно:
#include <iostream>
int main()
{
for ( auto i : { 1,2,3,4,5 } )
{
std::cout<<i<<std::endl;
}
}
Если вы не против выполнить цикл в обратном порядке, вы можете заменить
for (int i=0; i<n; ++i)
с более простым
for (int i=n; i--;)
В зависимости от того, что вы должны делать с целым числом, рассмотрите также <numeric>
заголовок, в частности std::iota в сочетании с std::transform и std::fill в зависимости от случаев.
Что ж, мне очень нравится решение, представленное здесь (извините, оно не переведено на английский):
#define FOR(I,UPPERBND) for(int I = 0; I<int(UPPERBND); ++I)
Основная идея описывается так: когда мы говорим о простых индексированных циклами итераций, нам не нужно об этом думать. Однако, когда мы используем конструкцию for(;;), всегда есть три шага: инициализация, проверка конечного условия, итерация. И это перебор для такого простого цикла, как просто i:[0,n). Мне понравилась идея, что мы хотим писать простые вещи простым способом. Когда вы видите это FOR(i,N) - вы просто понимаете, что в этом нет ничего особенного. Когда вы видите конструкцию for(;;) - нужно быть внимательнее и увидеть все три ее части. Просто пример из той статьи:
for (int iter=0; iter<nb_iter; iter++) { // some iterative computation
for (int c=0; c<mesh.cells.nb(); c++) // loop through all tetrahedra
for (int lv0=0; lv0<4; lv0++) // for every pair of
for (int lv1 = lv0+1; lv1<4; lv1++) // vertices in the tet
for (int d=0; d<3; d++) { // do stuff for each of 3 dimensions
nlRowScaling(weight);
nlBegin(NL_ROW);
nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d, 1);
nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
nlEnd(NL_ROW);
}
[...]
}
стать:
FOR(iter, nb_iter) {
FOR(c, mesh.cells.nb())
FOR(lv0, 4)
for (int lv1 = lv0+1; lv1<4; lv1++)
FOR(d, 3) {
nlRowScaling(weight);
nlBegin(NL_ROW);
nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d, 1);
nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
nlEnd(NL_ROW);
}
[...]
}
И вы видите, на чем следует сосредоточить свое внимание.