Улучшенные циклы в C++
я переключаюсь с Java на C++, и мне было интересно, содержит ли C++ расширенные циклы for, которые я использовал в java, например:
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for (int item : numbers) {
System.out.println("Count is: " + item);
}
возможен ли такой же "ярлык" в C++?
7 ответов:
В C++11, Если ваш компилятор поддерживает его, да. Это называется ассортимент для.
std::vector<int> v; // fill vector for (const int& i : v) { std::cout << i << "\n"; }он работает для массивов стиля C и любого типа, который имеет функции
begin()иend(), которые возвращают итераторы. Пример:class test { int* array; size_t size; public: test(size_t n) : array(new int[n]), size(n) { for (int i = 0; i < n; i++) { array[i] = i; } } ~test() { delete [] array; } int* begin() { return array; } int* end() { return array + size; } }; int main() { test T(10); for (auto& i : T) { std::cout << i; // prints 0123456789 } }
В C++11 нет. Они называются форс на основе диапазона. Помните, что вы должны определить тип как ссылку или ссылку на const.
обходной путь для C++03 является BOOST_FOR_EACH или boost:: bind в сочетании с std:: for_each. Более причудливые вещи возможны с повышением.Лямбда. Если вы будете в настроении, чтобы расстроить себя или своих коллег, я рекомендую устаревшие связующие
std::bind1stиstd::bind2nd.вот пример кода:
#include <iostream> #include <vector> #include <algorithm> #include <iterator> #include <boost/lambda/lambda.hpp> #include <functional> int main() { int i = 0; std::vector<int> v; std::generate_n(std::back_inserter(v), 10, [&]() {return i++;}); // range-based for // keep it simple for(auto a : v) std::cout << a << " "; std::cout << std::endl; // lambda // i don't like loops std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; }); std::cout << std::endl; // hardcore // i know my lib std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; // boost lambda // this is what google came up with // using for the placeholder, otherwise this looks weird using namespace boost::lambda; std::for_each(v.begin(), v.end(), std::cout << _1 << " "); std::cout << std::endl; // fold // i want to be a haskell programmer std::accumulate(v.begin(), v.end(), std::ref(std::cout), [](std::ostream& o, int i) -> std::ostream& { return o << i << " "; }); return 0; }
в C++03 такой возможности нет. Однако новый стандарт (C++11) имеет его. См. пример (взято из Википедия):
int my_array[5] = {1, 2, 3, 4, 5}; for (int &x : my_array) { x *= 2; }рассмотрите также использование
std::vector<int>вместо обычного массива. Это аналогия C++ для типов данных C, что упрощает жизнь.
да и нет.
1. Локальный массив: нет, но вы можете легко найти размер
если у вас есть локальный массив (
int numbers[4] = {1, 2, 3, 4];), то вы можете сделатьsize = sizeof(numbers) / sizeof(int).2. Указатель на массив: вовсе нет, вы должны передать размер вокруг отдельно
если у вас есть указатель на массив (
int* numbers = new int[4];) тогда вы не можете выяснить размер, если вы не отслеживать его самостоятельно. (или если это null завершается в случае c строка, но затем вы должны перебирать ее, что является линейным временем выполнения...)обратите внимание, что я не считаю, что указатель на массив является правильной терминологией, на самом деле у вас просто есть указатель на первый элемент массива, но пространство для нескольких значений было выделено. Не знаю, как это называется. Может быть, просто указатель?
3. Контейнеры STL: да, и вы можете сделать некоторые для циклической магии с помощью итераторов или просто использовать индексы, получая размер
если у вас есть вектор (
std::vector<int> v(3, 0);) затем вы можете перебирать его следующими способами:C++11:
auto it = v.begin(); for (auto it = v.begin(); it != v.end(); it++) { UseElement(*it); }или, по-видимому (также C++11, спасибо jrok):
for (const int& i : v) { UseElement(i); }C++ (pre-11):
std::vector<int>::iterator it; for (it = v.begin(); it != v.end(); it++) { UseElement(*it); }или с помощью индексов:
for (int i = 0; i < v.size(); i++) { UseElement(v[i]); }кроме того, вы можете использовать указатели функций или функторы с контейнерами STL, используя алгоритм std for_each (
#include <algorithm>) вот так:void foo(int i) { std::cout << i; } { std::for_each(myvector.begin(), myvector.end(), foo); }
другие уже упоминали, что этот стиль цикла был добавлен в C++11. Однако C++11 еще лучше:
for (auto const& item: numbers) { std::cout << "Count is: " << item << '\n'; }таким образом, если вы позже измените тип элемента
numbersСintдоlong, или даже в какой-тоbigintкласс, который вы написали сами, вам не нужно менять это для цикла на всех.
в старом стандарте, C++03 (который с 2003 года), язык не имеет встроенной поддержки для такого рода for-loop. Есть некоторые хитрости, которые вы можете использовать с Boost, но imo не стоит включать целую новую библиотеку для этой небольшой функции удобства.
в новом стандарте, C++11 (который был выпущен только прошлым летом), это возможно; синтаксис выглядит так:
MyType array[] = { ... } for (MyType& x : array) { ... }обратите внимание, что я использую
MyType& x, а неMyType x. В Java все является ссылка. В C++ ссылки должны быть явными, а вы объявляете их с помощью&. Если вы не используете ссылки, for-loop будет копировать каждый элемент массива вx(что может быть дорого).однако, C++11 еще не полностью поддерживается большинством компиляторов. Я думаю, что Visual C++ Microsoft поддерживает эту функцию, но я не уверен.
Я нахожу этот простой макрос очень полезен. Подавляющее большинство моих
forциклы включают итерацию по контейнеру STL:#define For(it, container) for( typeof((container).begin()) it = (container).begin(); it != (container).end(); ++it)пример:
vector<int> vector_of_ints; ... // initialize it somehow For(integer, vector_of_ints) { cout << *integer << endl; }есть две вещи, чтобы быть в курсе с этим: во-первых, это итератор, и, следовательно, вы должны разыменовать его. А во-вторых, второй параметр к
Forбудет вычисляться много раз. Я играл с другими подходами, но я продолжаю возвращаться к простоте этого.
Comments