Можно ли объявить две переменные разных типов в цикле for? - PullRequest
211 голосов
/ 22 апреля 2010

Можно ли объявить две переменные разных типов в теле инициализации цикла for в C ++?

Например:

for(int i=0,j=0 ...

определяет два целых числа.Могу ли я определить int и char в теле инициализации?Как это будет сделано?

Ответы [ 7 ]

263 голосов
/ 22 апреля 2010

Нет - но технически есть обходной путь (не то, чтобы я использовал его, если не принуждал):

for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a) 
{
    std::cout << s.a << " " << s.b << std::endl;
}
203 голосов
/ 22 апреля 2010

Невозможно, но вы можете сделать:

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++)
    {
       //...
    }
}
106 голосов
/ 29 августа 2013

C ++ 17 : Да! Вы должны использовать объявление структурированной привязки . Синтаксис поддерживается в gcc-7 и clang-4.0 ( clang live example ). Это позволяет нам распаковать кортеж так:

for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"abc"}}; i < N; ++i) {
    // ...
}

Сказанное выше даст вам:

  • int i установлено на 1
  • double f установлено на 1.0
  • std::string s установлено на "abc"

Обязательно #include <tuple> для такого рода декларации.

Вы можете указать точные типы внутри tuple, напечатав их все как у меня с std::string, если вы хотите назвать тип. Например:

auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}

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 и выражения обновления

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 Вы можете явно назвать типы std::pair. Не существует стандартного способа обобщить это более чем на два типа:

for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
    std::cout << p.second << std::endl;
}
14 голосов
/ 22 апреля 2010

Вы не можете объявить несколько типов при инициализации, но вы можете назначить несколько типов E.G.

{
   int i;
   char x;
   for(i = 0, x = 'p'; ...){
      ...
   }
}

Просто объявите их в своей области видимости.

1 голос
/ 12 ноября 2011

См. " Есть ли способ определить переменные двух типов в цикле for? " для другого способа, включающего вложение нескольких циклов for. Преимущество другого способа перед «структурным приемом» Георга состоит в том, что он (1) позволяет вам иметь смесь статических и нестатических локальных переменных и (2) позволяет иметь непереписываемые переменные. Недостатком является то, что он гораздо менее читабелен и может быть менее эффективным.

0 голосов
/ 23 мая 2019

Я думаю, что лучший подход - это ответ Сианя .

но ...


# Вложено для цикла

Этот подход грязный, но может решить любую версию.

Итак, я часто использую его в макро-функциях.

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
    }

Дополнительно 1.

Может также использоваться для 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.
    }

Дополнительно 2.

Хороший пример: с функцией макроса.

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

#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

if (A* a=nullptr);
else
    for(...) // a is visible

Если вы хотите инициализировать 0 или nullptr, вы можете использовать этот трюк.

но я не рекомендую это из-за трудного чтения.

и похоже на ошибку.

0 голосов
/ 20 июля 2013

Определить макрос:

#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.

...