Итерация по std :: vector: переменная индекса без знака и со знаком

Как правильно перебирать вектор в C++?

Рассмотрим эти два фрагмента кода, этот отлично работает:

for (unsigned i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

и этот:

for (int i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

который генерирует warning: comparison between signed and unsigned integer expressions.

Я новичок в мире C++, поэтому переменная unsigned выглядит для меня немного пугающей, и я знаю, что переменные unsigned могут быть опасны, если используются неправильно, так что - это правильно?

Беззнаковый правильный, потому что polygon.size () имеет тип беззнаковый. Беззнаковый означает всегда положительный или 0. Вот и все, что это значит. Так что, если переменная всегда используется только для подсчета, то правильный выбор - беззнаковый.

Adam Bruss 10.10.2013 20:42

Чтобы устранить предупреждение о подписанном / неподписанном, просто замените int на uint (unsigned int) в декларации i.

Honza 21.12.2014 21:30

@AdamBruss .size() не относится к типу unsigned, также известному как unsigned int. Это типа std::size_t.

underscore_d 26.06.2016 13:15

@underscore_d size_t - это псевдоним для unsigned.

Adam Bruss 27.06.2016 16:39

@AdamBruss Нет. std::size_t - это typedef, определенный _ реализацией. См. Стандарт. std::size_t может быть эквивалентом unsigned в вашей текущей реализации, но это не имеет значения. Представление, что это так, может привести к непереносимому коду и неопределенному поведению.

underscore_d 27.06.2016 16:45

@underscore_d В какой версии C++ беззнаковый не эквивалентен size_t?

Adam Bruss 28.06.2016 17:16

@underscore_d Я был неправ, говоря, что unsigned эквивалентно size_t. size_t составляет 8 байтов при 64-битной сборке, как вы указали. Это верно и для Microsoft Visual C++. Но если size_t действительно различался в двух компиляторах, как вы предполагаете, у вас был бы непереносимый код, просто используя size_t.

Adam Bruss 28.06.2016 18:22

@AdamBruss ... туше! Избитый, используя мою собственную логику, из-за чего моя тирада в моем последнем комментарии выглядела лицемерной :-) Да, поведение, определяемое реализацией, кажется гарантированным с такими определениями типов, независимо от того, используете ли вы их или игнорируете. Я бы сказал, что, возможно, лучше использовать их там, где это возможно, даже если выгода чисто теоретическая - но сравните это с другими потоками, где люди утверждают, что std::size_t в значительной степени бессмысленен, и все обычные циклы должны выполняться с int! Думаю, это не совсем практические темы, так как мало кто когда-либо будет использовать такие большие массивы.

underscore_d 28.06.2016 18:31

@underscore_d Я полагаю, что size_t - необходимое зло, позволяющее, например, разрешить одну функцию size () вместо той, которая возвращает 4 байта без знака, а другая возвращает 8 байтов без знака. Я согласен насчет больших контейнеров.

Adam Bruss 30.06.2016 19:35

@underscore_d Это не типа size_t, а типа decltype(polygon)::size_type.

L. F. 31.07.2019 04:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
484
10
832 822
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

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

for (size_t i=0; i < polygon.size(); i++)

Цитата Википедия:

The stdlib.h and stddef.h header files define a datatype called size_t which is used to represent the size of an object. Library functions that take sizes expect them to be of type size_t, and the sizeof operator evaluates to size_t.

The actual type of size_t is platform-dependent; a common mistake is to assume size_t is the same as unsigned int, which can lead to programming errors, particularly as 64-bit architectures become more prevalent.

size_t Хорошо для вектора, так как он должен хранить все объекты в массиве (сам объект тоже), но std :: list может содержать больше, чем size_t элементов!

MSalters 05.01.2009 12:57

size_t обычно достаточно для перечисления всех байтов в адресном пространстве процесса. Хотя я понимаю, что это может быть не так в некоторых экзотических архитектурах, я бы предпочел не беспокоиться об этом.

user3458 05.01.2009 21:54

AFAIK рекомендуется #include <cstddef>, а не <stddef.h> или, что еще хуже, [c]stdlib целиком, и использовать std::size_t, а не неквалифицированную версию - и то же самое для любой другой ситуации, когда у вас есть выбор между <cheader> и <header.h>.

underscore_d 26.06.2016 13:24

Вызов vector<T>::size() возвращает значение типа std::vector<T>::size_type, а не int, unsigned int или иное.

Также обычно итерация по контейнеру в C++ выполняется с использованием итераторы, как это.

std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();

for(; i != end; i++){
    sum += *i;
}

Где T - это тип данных, которые вы храните в векторе.

Или с использованием различных итерационных алгоритмов (std::transform, std::copy, std::fill, std::for_each и так далее).

Итераторы, как правило, являются хорошей идеей, хотя я сомневаюсь, что есть необходимость хранить «конец» в отдельной переменной, и все это можно сделать внутри оператора for (;;).

Saulius Žemaitaitis 03.01.2009 20:03

Я знаю, что begin () и end () - это амортизируемое постоянное время, но я обычно считаю, что это более читабельно, чем втискивать все в одну строку.

Jasper Bekkers 03.01.2009 20:06

Вы можете разделить for на отдельные строки, чтобы улучшить читаемость. Объявление итераторов вне цикла означает, что вам нужно другое имя итератора для каждого цикла по контейнерам разных типов.

Jay Conrod 03.01.2009 20:43

Я знаю обо всех различиях, и в основном это сводится к личным предпочтениям; Обычно так я и поступаю.

Jasper Bekkers 04.01.2009 21:23

обычно рекомендуется сохранять результат end () в переменной, чтобы избежать повторного вызова функции. даже если это постоянное время, все равно будут накладные расходы на выполнение вызова. нет причин для инициализации вне цикла, и единственный результат этого - загромождение области.

user44511 04.01.2009 21:43

@ user44511: так что вы предлагаете?

pihentagy 28.06.2011 13:31

@pihentagy Я думаю, это было бы установить его в первом разделе цикла for. например. for (auto i = polygon.begin (), end = polygon.end (); i! = end; i ++)

Jasper Bekkers 09.01.2014 00:58

любая операция, которая делает недействительными итераторы, также потенциально делает недействительным end ()

sp2danny 12.11.2014 13:44
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 

Для вектора это нормально, но в целом лучше использовать ++ it, а не it ++, в случае, если сам итератор нетривиален.

Steve Jessop 04.01.2009 16:50

Лично я привык использовать ++ i, но думаю, что большинство людей предпочитают стиль i ++ (фрагмент кода VS по умолчанию для "for" - это i ++). Просто мысль

mmx 04.01.2009 21:31

@MehrdadAfshari Кого волнует, что делают «большинство людей»? «большинство людей» ошибаются во многих вещах. Пост-инкремент / декремент, когда значение pre никогда не используется, неверно и неэффективно, по крайней мере, теоретически - независимо от того, как часто оно вслепую используется во всех примерах кода sub-par. Вы не должны поощрять плохие практики только для того, чтобы сделать вещи более знакомыми для людей, которые еще не знают лучшего.

underscore_d 26.06.2016 13:27

Немного истории:

Чтобы указать, является ли число отрицательным или нет, компьютер использует «знаковый» бит. int - это тип данных со знаком, что означает, что он может содержать положительные и отрицательные значения (от -2 до 2 миллиардов). Unsigned может хранить только положительные числа (и, поскольку он не тратит немного времени на метаданные, он может хранить больше: от 0 до примерно 4 миллиардов).

std::vector::size() возвращает unsigned, почему вектор может иметь отрицательную длину?

Предупреждение говорит вам, что правый операнд вашего оператора неравенства может содержать больше данных, чем левый.

По сути, если у вас есть вектор с более чем 2 миллиардами записей и вы используете целое число для индексации, вы столкнетесь с проблемами переполнения (int вернется к отрицательным 2 миллиардам).

Первый - это правильный тип и правильный в некотором строгом смысле слова. (Если задуматься, размер никогда не может быть меньше нуля.) Однако это предупреждение кажется мне одним из хороших кандидатов на игнорирование.

Я считаю, что это ужасный кандидат для игнорирования - его легко исправить, и время от времени возникают настоящие ошибки из-за ошибок при неправильном сравнении подписанных / неподписанных значений. Например, в этом случае, если размер больше INT_MAX, цикл никогда не завершается.

Steve Jessop 04.01.2009 16:54

... или, может быть, он немедленно прекращается. Один из двух. Зависит от того, преобразовано ли значение со знаком в беззнаковое для сравнения или беззнаковое преобразовано в знаковое. Однако на 64-битной платформе с 32-битным int, как и в win64, int будет повышен до size_t, и цикл никогда не закончится.

Steve Jessop 04.01.2009 17:28

@SteveJessop: Нельзя с уверенностью сказать, что цикл никогда не закончится. На итерации, когда i == INT_MAX, i++ вызывает неопределенное поведение. Здесь может случиться что угодно.

Ben Voigt 16.10.2014 21:21

@BenVoigt: правда, и все же не дает оснований игнорировать предупреждение :-)

Steve Jessop 19.10.2014 16:35
Ответ принят как подходящий

Для итерации в обратном направлении см. этот ответ.

Итерация вперед практически идентична. Просто измените итераторы / декремент свопа на инкремент. Вам следует предпочесть итераторы. Некоторые люди советуют использовать std::size_t в качестве типа индексной переменной. Однако это непереносимо. Всегда используйте size_type typedef контейнера (хотя вы можете обойтись только преобразованием в случае прямой итерации, на самом деле она может пойти не так, как в случае обратной итерации при использовании std::size_t, в случае, если std::size_t шире, чем то, что typedef size_type):


Использование std :: vector

Использование итераторов

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    /* std::cout << *it; ... */
}

Важно всегда использовать форму приращения префикса для итераторов, определения которых вам неизвестны. Это гарантирует, что ваш код будет работать как можно более универсальным.

Использование Range C++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Использование индексов

for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
    /* std::cout << v[i]; ... */
}

Использование массивов

Использование итераторов

for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
    /* std::cout << *it; ... */
}

Использование Range C++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Использование индексов

for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
    /* std::cout << a[i]; ... */
}

Прочтите в ответе на обратную итерацию, какую проблему может решить подход sizeof.

тип указателей размера: использование Difference_type может быть более переносимым. попробуйте iterator_traits <element_type *> :: difference_type. это полнейшая декларация, но она более портативна ...

wilhelmtell 04.01.2009 07:48

Вильгельмтелл, для чего мне использовать разницу_тип? sizeof должен возвращать size_t :) я вас не понимаю. если бы мне пришлось вычитать указатели друг из друга, «разница_тип» была бы правильным выбором.

Johannes Schaub - litb 04.01.2009 12:38

итерация по массивам с использованием техники, которую вы упомянули в этом посте, не будет работать, если итерация выполняется в функции в массиве, переданном этой функции. Потому что массив sizeof вернет только указатель sizeof.

systemsfault 07.06.2011 12:33

Согласно этому руководству [1] использование счетчиков циклов без подписи - плохая идея. Поэтому, вероятно, следует сначала указать размер в подписанном int. [1] developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/‌…

Nils 23.02.2012 19:03

@Nils Я согласен с тем, что использование счетчиков циклов без знака - плохая идея. но поскольку стандартная библиотека использует беззнаковые целочисленные типы для индекса и размера, я предпочитаю беззнаковые индексные типы для стандартной библиотеки. следовательно, другие библиотеки используют только подписанные типы, такие как Qt lib.

Johannes Schaub - litb 11.03.2012 20:53

Обновление для C++ 11: цикл for на основе диапазона. for (auto p : polygon){sum += p;}

Siyuan Ren 22.08.2013 08:56

@ C.R. также обновление для C++ 11: используйте std::begin() и std::end(), чтобы сделать версию массива и векторной версии равной.

Manu343726 19.10.2013 19:01

@StackedCrooked Около года назад я опубликовал ответ C++ 11, см. Ниже: stackoverflow.com/questions/409348/iteration-over-vector-in-‌ c /…

kratenko 29.04.2014 13:27

если вам нужно использовать индекс цикла и вам лень набирать полный size_type контейнера, рассмотрите еще одну функцию C++ 11 decltype, как в for (decltype(vec.size()) i=0; i<vec.size(); ++i)

Yibo Yang 25.05.2017 09:05

@ JohannesSchaub-litb Пример "Использование std :: vector / Использование диапазона C++ 11" мне кажется неправильным. Откуда взялось требование "const &"? Разве пример не должен быть: for(auto i : v) { /* std::cout << i; ... */ }?

Thomas 10.06.2020 13:12

Обычно я использую BOOST_FOREACH:

#include <boost/foreach.hpp>

BOOST_FOREACH( vector_type::value_type& value, v ) {
    // do something with 'value'
}

Он работает с контейнерами STL, массивами, строками в стиле C и т. д.

Хороший ответ на другой вопрос (как мне перебрать вектор?), Но совершенно не то, что спрашивал OP (в чем смысл предупреждения о беззнаковой переменной?)

abelenky 03.01.2009 20:39

Ну, он спросил, как правильно перебирать вектор. Так что кажется достаточно актуальным. Предупреждение объясняет, почему он недоволен своим текущим решением.

jalf 03.01.2009 21:14

В конкретном случае в вашем примере я бы использовал алгоритмы STL для этого.

#include <numeric> 

sum = std::accumulate( polygon.begin(), polygon.end(), 0 );

Для более общего, но все же довольно простого случая я бы выбрал:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );

Что касается ответа Йоханнеса Шауба:

for(std::vector<T*>::iterator it = v.begin(); it != v.end(); ++it) { 
...
}

Это может работать с некоторыми компиляторами, но не с gcc. Проблема здесь в том, является ли std :: vector :: iterator типом, переменной (членом) или функцией (методом). Мы получаем следующую ошибку с gcc:

In member function ‘void MyClass<T>::myMethod()’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In member function ‘void MyClass<T>::sort() [with T = MyClass]’:
instantiated from ‘void MyClass<T>::run() [with T = MyClass]’
instantiated from here
dependent-name ‘std::vector<T*,std::allocator<T*> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<T*,std::allocator<T*> >::iterator’ if a type is meant

Решение использует ключевое слово typename, как сказано:

typename std::vector<T*>::iterator it = v.begin();
for( ; it != v.end(); ++it) {
...

Следует уточнить, что это применимо только тогда, когда T является аргументом шаблона, и, следовательно, выражение std::vector<T*>::iterator является зависимым именем. Чтобы зависимое имя было проанализировано как тип, перед ним должно стоять ключевое слово typename, как показывает диагностика.

Kuba hasn't forgotten Monica 31.07.2014 17:22

Прошло четыре года, и Google дал мне такой ответ. С стандартный C++ 11 (он же C++ 0x) есть новый приятный способ сделать это (ценой нарушения обратной совместимости): новое ключевое слово auto. Это избавляет вас от необходимости явно указывать тип используемого итератора (повторяя векторный тип снова), когда очевидно (для компилятора), какой тип использовать. Если v является вашим vector, вы можете сделать что-то вроде этого:

for ( auto i = v.begin(); i != v.end(); i++ ) {
    std::cout << *i << std::endl;
}

C++ 11 идет еще дальше и дает вам специальный синтаксис для итерации по коллекциям, таким как векторы. Это устраняет необходимость писать всегда одно и то же:

for ( auto &i : v ) {
    std::cout << i << std::endl;
}

Чтобы увидеть это в работающей программе, соберите файл auto.cpp:

#include <vector>
#include <iostream>

int main(void) {
    std::vector<int> v = std::vector<int>();
    v.push_back(17);
    v.push_back(12);
    v.push_back(23);
    v.push_back(42);
    for ( auto &i : v ) {
        std::cout << i << std::endl;
    }
    return 0;
}

На момент написания этого, когда вы компилируете это с помощью g ++, вам обычно нужно настроить его для работы с новым стандартом, указав дополнительный флаг:

g++ -std=c++0x -o auto auto.cpp

Теперь вы можете запустить пример:

$ ./auto
17
12
23
42

Пожалуйста, обрати внимание, что инструкции по компиляции и запуску относятся к компилятору GNU C++ на Linux, программа должна быть независимой от платформы (и компилятора).

C++ 11 дает вам for (auto& val: vec)

Flexo 05.03.2013 22:57

@flexo Спасибо, я не знаю, как я мог это забыть. Думаю, недостаточно много C++. Не мог поверить, что есть что-то настолько практичное (на самом деле, думал, что это синтаксис JavaScript). Я изменил ответ, включив это.

kratenko 08.03.2013 13:34

Ваш ответ очень хороший. К сожалению, версия g ++ по умолчанию в различных наборах ОС не ниже 4.3, поэтому она не работает.

Ratata Tata 28.08.2013 18:05

Вам нужно инициализировать вектор с помощью std::vector<int> v = std::vector<int>();, или вы могли бы просто использовать вместо него std::vector<int> v;?

Bill Cheatham 27.03.2016 16:59

@BillCheatham Ну, я просто попробовал это без инициализации, и он работал, так что кажется, что он работает без.

kratenko 27.03.2016 18:08

Спасибо, да, у меня это сработало, но я подумал, не повезло ли мне просто с памятью и не получил segfault. Я полагаю, у std::vector не должно быть тех же проблем, что и у массивов ...?

Bill Cheatham 27.03.2016 18:40

Мне кажется странным, что вы написали ответ, восхваляющий новые возможности C++ 11, но при этом инициализировали свой контейнер, например что, вместо использования std::initializer_list C++ 11, который существует именно для того, чтобы избежать такого шаблона. Просто сделайте это: std::vector<int> v{17, 12, 23, 42};. Это позволяет избежать ненужной конструкции по умолчанию из еще более ненужного временного и повторяющегося push_back() - и, кстати, мы должны по умолчанию использовать еще одну новую вещь C++ 11, emplace_back(), поскольку, по крайней мере, для более сложных объектов push может генерировать ненужные копирующие конструкции. .

underscore_d 26.06.2016 13:17

Вам не нужен & для доступа только для чтения, и я думаю, что здесь лучше int, чем auto: я бы использовал: for (int i: v)

Will 19.06.2017 12:52

Я хотел бы знать, как "for (auto & val: vec)" работает внутренне, использует итератор внутри и функции begin (), end () класса vector?

vin 05.11.2020 08:46

Чтобы быть полным, синтаксис C++ 11 позволяет использовать только одну другую версию для итераторов (ссылка):

for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
  // do something with *it
}

Что также удобно для обратной итерации

for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
  // do something with *it
}

В C++ 11

Я бы использовал общие алгоритмы, такие как for_each, чтобы избежать поиска правильного типа итератора и лямбда-выражения, чтобы избежать дополнительных именованных функций / объектов.

Короткий "красивый" пример для вашего конкретного случая (при условии, что многоугольник является вектором целых чисел):

for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; });

проверено на: http://ideone.com/i6Ethd

Не забудьте про алгоритм включать: и, конечно же, вектор :)

У Microsoft есть хороший пример по этому поводу:
источник: http://msdn.microsoft.com/en-us/library/dd293608.aspx

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() 
{
   // Create a vector object that contains 10 elements.
   vector<int> v;
   for (int i = 1; i < 10; ++i) {
      v.push_back(i);
   }

   // Count the number of even numbers in the vector by 
   // using the for_each function and a lambda.
   int evenCount = 0;
   for_each(v.begin(), v.end(), [&evenCount] (int n) {
      cout << n;
      if (n % 2 == 0) {
         cout << " is even " << endl;
         ++evenCount;
      } else {
         cout << " is odd " << endl;
      }
   });

   // Print the count of even numbers to the console.
   cout << "There are " << evenCount 
        << " even numbers in the vector." << endl;
}

Подумайте, нужно ли вам вообще повторять

Стандартный заголовок <algorithm> предоставляет нам возможности для этого:

using std::begin;  // allows argument-dependent lookup even
using std::end;    // if the container type is unknown here
auto sum = std::accumulate(begin(polygon), end(polygon), 0);

Другие функции библиотеки алгоритмов выполняют общие задачи - убедитесь, что вы знаете, что доступно, если хотите сэкономить силы.

Непонятная, но важная деталь: если вы скажете «for (auto it)» следующим образом, вы получите копию объекта, а не фактический элемент:

struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
    it.i = 1;         // doesn't change the element v[0]

Чтобы изменить элементы вектора, вам нужно определить итератор как ссылку:

for(auto &it : v)

Если ваш компилятор поддерживает это, вы можете использовать диапазон на основе для доступа к векторным элементам:

vector<float> vertices{ 1.0, 2.0, 3.0 };

for(float vertex: vertices){
    std::cout << vertex << " ";
}

Отпечатки: 1 2 3. Обратите внимание, что вы не можете использовать эту технику для изменения элементов вектора.

Два сегмента кода работают одинаково. Однако маршрут unsigned int "правильный. Использование типов int без знака будет лучше работать с вектором в том экземпляре, который вы его использовали. Вызов функции-члена size () для вектора возвращает целочисленное значение без знака, поэтому вы хотите сравнить переменную "i" к значению собственного типа.

Кроме того, если вас все еще немного беспокоит, как "unsigned int" выглядит в вашем коде, попробуйте "uint". По сути, это сокращенная версия unsigned int, работающая точно так же. Вам также не нужно включать другие заголовки, чтобы использовать его.

Целое число без знака для size () не обязательно равно «unsigned int» в терминах C++, часто «целое число без знака» в этом случае представляет собой 64-битное целое число без знака, тогда как «unsigned int» обычно 32-битное.

Medran 07.03.2019 19:12

Добавляя это, поскольку я не мог найти его ни в одном ответе: для итерации на основе индекса мы можем использовать decltype(vec_name.size()), который будет оценивать std::vector<T>::size_type

Пример

for(decltype(v.size()) i{ 0 }; i < v.size(); i++) {
    /* std::cout << v[i]; ... */
}

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