2015-04-08 3 views
11

На самом деле это два связанных вопроса.Сокращение for-loop - синтаксический сахар в 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]){ ... } 

было бы здорово.

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

+2

Если вы хотите, чтобы * заполнить вектор значением j в позиции j *, вы можете использовать [std :: iota()] (http://en.cppreference.com/w/cpp/algorithm/iota) –

+3

Один вопрос одновременно, пожалуйста. Затем мы можем закрыть каждый из них как дубликат ранее существовавшего вопроса, который вы не искали. :) –

+0

@ Антон Thx для iota! Его не _все_ я хочу, но это, конечно, хорошо знать. – dingalapadum

ответ

9

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

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

for (int i : boost::irange(0, 100)) 
+0

ok. спасибо. но я бы хотел избежать использования дополнительных libs только для этого. Я отредактирую свой вопрос. – dingalapadum

+5

@dingalapadum Вы избавитесь от мира боли и переосмысления колес, если не подумайте о том, что Boost «дополнительная библиотека». Просто рассматривайте это как «стандартное дополнение к библиотеке». – Angew

+1

@Angew Даже если сегодня в большинстве систем присутствует повышение, это делает компиляцию медленнее, а иногда и немного нестабильной, поскольку рост числа увеличивается. Так что это респектабельный выбор, чтобы не хотеть использовать его. – Aracthor

18

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

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

#include <boost/range/irange.hpp> 

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

Используйте это:

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

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

1

Если 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 принимает два или более Iterable диапазонов (или контейнеров) и производит вид диапазона над кортежами iterator_traits<It>::reference с до элементов.

Здесь находится итератор Boost zip: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html - есть ли диапазон увеличения, который обрабатывает синтаксис, как указано выше zip.

3

На второй вопрос - если 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 и только заголовок.

0

Что касается второго вопроса, если вы используете последние версии Visual Studio, типа «если», то Tab, Tab и Tab заполнить значение инициализации, шаг и так далее.

2

Вы можете сделать обе эти вещи с 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 
1

Для 2-й вопрос:

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

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

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

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

+0

Интересно. что будет «я» в этом случае? Создает ли это новый вектор bools размером 10? Или что здесь происходит? – dingalapadum

+0

Да, он создает вектор размером 10, является абсолютизированным преувеличением цели, но возможно. ;) 'i' будет неинициализированными булевыми значениями вектора. – Stuck

+0

Хорошо. вроде дорогой петли ... Мне бы очень хотелось, чтобы я поднял голову, потому что я нахожу ее творческой ... опять же, я никогда не буду использовать это или рекомендовать это кому-либо ... также, это не похоже на сокращенный или синтаксический сахар , Тем не менее, если вы разместите те детали, которые вы упомянули в сообщении, и уточните недостатки, которые я готов поддержать в качестве вознаграждения за эти усилия. – dingalapadum

Смежные вопросы