Можно ли объявить две переменные разных типов в теле инициализации цикла for в C ++?
Например:
for(int i=0,j=0 ...
определяет два целых числа Могу ли я определить int
и char
в теле инициализации? Как это будет сделано?
Можно ли объявить две переменные разных типов в теле инициализации цикла for в C ++?
Например:
for(int i=0,j=0 ...
определяет два целых числа Могу ли я определить int
и char
в теле инициализации? Как это будет сделано?
Ответы:
C ++ 17 : Да! Вы должны использовать объявление структурированной привязки . Синтаксис поддерживается в gcc и clang в течение многих лет (начиная с gcc-7 и clang-4.0) ( живой пример clang ). Это позволяет нам распаковать кортеж так:
for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}
Вышеуказанное даст вам:
int i
установлен в 1
double f
установлен в 1.0
std::string s
установлен в "ab"
Обязательно #include <tuple>
для такого рода деклараций.
Вы можете указать точные типы внутри tuple
, напечатав их все как у меня std::string
, если вы хотите назвать тип. Например:
auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}
Конкретным применением этого является итерация по карте, получение ключа и значения,
std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}
Смотрите живой пример здесь
C ++ 14 : вы можете сделать то же самое, что и C ++ 11 (ниже), с добавлением типов на основе std::get
. Таким образом, вместо std::get<0>(t)
приведенного ниже примера, вы можете иметь std::get<int>(t)
.
C ++ 11 : std::make_pair
позволяет сделать это, а также std::make_tuple
для более чем двух объектов.
for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << std::endl;
}
std::make_pair
вернет два аргумента в std::pair
. Элементы могут быть доступны с помощью .first
и .second
.
Для более чем двух объектов вам нужно использовать std::tuple
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
std::cout << std::get<1>(t) << std::endl; // cout Hello world
std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}
std::make_tuple
шаблон с переменным числом аргументов, который будет создавать кортеж из любого числа аргументов (с некоторыми техническими ограничениями, конечно). Элементы могут быть доступны по индексу сstd::get<INDEX>(tuple_object)
В теле цикла for вы можете легко создавать псевдонимы для объектов, хотя вам все равно нужно использовать .first
или std::get
для условия цикла for и выражения update
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
auto& i = std::get<0>(t);
auto& s = std::get<1>(t);
auto& v = std::get<2>(t);
std::cout << s << std::endl; // cout Hello world
v.push_back(i); // add counter value to the vector
}
C ++ 98 и C ++ 03 Вы можете явно назвать типы a std::pair
. Не существует стандартного способа обобщить это более чем на два типа:
for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
std::cout << p.second << std::endl;
}
make_
и написать std::pair(1, 1.0)
.
Нет, но технически есть обходной путь (не то, чтобы я использовал его, если бы не был вынужден):
for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a)
{
std::cout << s.a << " " << s.b << std::endl;
}
struct { int a=0; char b='a'; } s;
Не возможно, но вы можете сделать:
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
Или явно ограничьте область применения f
и i
используйте дополнительные скобки:
{
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
}
Я думаю, что лучший подход - это ответ Сианя .
но...
Этот подход грязен, но может решить любую версию.
поэтому я часто использую его в макросах.
for(int _int=0, /* make local variable */ \
loopOnce=true; loopOnce==true; loopOnce=false)
for(char _char=0; _char<3; _char++)
{
// do anything with
// _int, _char
}
Это также может быть использовано для declare local variables
и initialize global variables
.
float globalFloat;
for(int localInt=0, /* decalre local variable */ \
_=1;_;_=0)
for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
{
// do.
}
Хороший пример: с функцией макроса.
(Если лучший подход не может быть использован, потому что это макрос for-loop)
#define for_two_decl(_decl_1, _decl_2, cond, incr) \
for(_decl_1, _=1;_;_=0)\
for(_decl_2; (cond); (incr))
for_two_decl(int i=0, char c=0, i<3, i++)
{
// your body with
// i, c
}
if (A* a=nullptr);
else
for(...) // a is visible
Если вы хотите инициализировать в 0
или nullptr
, вы можете использовать этот трюк.
но я не рекомендую это из-за жесткого чтения.
и это похоже на ошибку.
См. « Есть ли способ определить переменные двух типов в цикле for? », Чтобы узнать о другом способе, заключающемся во вложении нескольких циклов for. Преимущество другого способа перед «структурным трюком» Георга состоит в том, что он (1) позволяет вам иметь смесь статических и нестатических локальных переменных и (2) позволяет иметь непереписываемые переменные. Недостатком является то, что он гораздо менее читабелен и может быть менее эффективным.
Определите макрос:
#define FOR( typeX,x,valueX, typeY,y,valueY, condition, increments) typeX x; typeY y; for(x=valueX,y=valueY;condition;increments)
FOR(int,i,0, int,f,0.0, i < 5, i++)
{
//...
}
Просто помните, что ваши переменные области также не будут в цикле for.
{
и }
.
-std=c++0x
) в формеfor(auto i=0, j=0.0; ...
, но эта возможность была удалена в g ++ - 4.5, чтобы совпадать с текстами c ++ 0x.