Чи можливо оголосити дві змінні різних типів в тілі ініціалізації циклу a для C ++?
Наприклад:
for(int i=0,j=0 ...
визначає два цілих числа. Чи можу я визначити а int
та а char
в тілі ініціалізації? Як би це було зроблено?
Чи можливо оголосити дві змінні різних типів в тілі ініціалізації циклу a для 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
поверне два аргументи в a 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 (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.
}
Хороший приклад: з макро функцією.
(Якщо найкращий підхід не може бути використаний, оскільки це макрос для циклу)
#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
, ви можете використовувати цей трюк.
але я не рекомендую цього через важке читання.
і, здається, помилка.
Див. " Чи існує спосіб визначення змінних двох типів для циклу? " Для іншого способу, що включає введення множин для циклів. Перевага іншого способу перед "структурним трюком" Георга полягає в тому, що він (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.