2010-04-22 10 views
155

Czy można zadeklarować dwie zmienne różnych typów w treści inicjującej pętli for w C++?Czy można zadeklarować dwie zmienne różnych typów w pętli for?

Na przykład

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

definiuje dwie liczby całkowite. Czy mogę zdefiniować int i char w treści inicjowania? Jak to się stało?

+3

Jest to możliwe w g ++ - 4.4 ('-std = C++ 0x') w postaci' for (i = 0 auto , j = 0.0; ... ', ale ta możliwość została usunięta w g ++ - 4.5, aby pokryć się z tekstami C++ 0x. – rafak

+0

możliwy duplikat [Czy mogę zadeklarować zmienne różnych typów w inicjalizacji pętli for?] (http://stackoverflow.com/questions/8644707/can-i-declare-variables-of-different-types-in--initialization-of-a-loop) –

+2

W rzeczywistości to inne pytanie powinno zostać zamknięte jako duplikat tego, ponieważ ma to lepsze odpowiedzi: –

Odpowiedz

160

niemożliwe, ale można to zrobić:

float f; 
int i; 
for (i = 0,f = 0.0; i < 5; i++) 
{ 
    //... 
} 

Albo wyraźnie ograniczyć zakres f i i stosowania dodatkowych uchwytów:

{ 
    float f; 
    int i; 
    for (i = 0,f = 0.0; i < 5; i++) 
    { 
     //... 
    } 
} 
+0

Ah, to wygląda na dobre rozwiązanie, zagłębię się w to: –

+0

Wiem, że to bardzo stare pytanie, ale czy możesz wyjaśnić, dlaczego niektóre zrobiłbym to z dodatkowymi nawiasami wokół niego, jak w twoim drugim przykładzie? – ford

+8

@fizzisist, aby wyraźnie ograniczyć zakres f i i tylko do części kodu, w którym są używane. –

13

Nie można deklarować wiele typów w inicjalizacji , ale możesz przypisać do wielu typów EG

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

Po prostu zadeklaruj je we własnym zakresie.

214

Nie - ale technicznie jest obejście (nie, że ja rzeczywiście go używać, chyba zmuszony):

for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a) 
{ 
    std::cout << s.a << " " << s.b << std::endl; 
} 
+49

upvoting dla wow. –

+1

To nie kompiluje się na VS 2008, ale ma na Comeau online ;-) – JRL

+6

@JRL: Oh, VS2005 też nie. Przypuszczam, że jest jeszcze jedna funkcja niezgodności w VC++. –

1

Patrz „Is there a way to define variables of two types in for loop?” w inny sposób z udziałem gniazdowania wielokrotność dla pętli. Zaletą "sztuczki strukturalnej" Georga jest to, że pozwala on (1) na połączenie zmiennych statycznych i niestatycznych lokalnych oraz (2) pozwala na posiadanie zmiennych, które nie mogą być kopiowane. Minusem jest to, że jest znacznie mniej czytelny i może być mniej wydajny.

-1

zdefiniować makro:

#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++) 
{ 
    //... 
} 

Wystarczy Pamiętaj, że zmienne zakresy nie będzie w ten sposób do pętli albo.

+0

Możesz łatwo przezwyciężyć to ograniczenie, zawijając kod w makrze w osobnym zakresie używając '{' i '}'. –

+4

Nie, nie mógł. Jego makro nie owija ciała pętli. Mógłby dodać dodatkowy uchwyt otwierający, ale wymagałoby to "dodatkowego" wspornika zamykającego podczas używania makra. – John

53

Dla C++ 17 należy użyć structured binding declaration. Składnia jest obsługiwana w gcc-7 i clang-4.0 (clang live example). To pozwala nam rozpakować krotka tak:

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

dla C++ 14 można zrobić to samo jak C++ 11 (poniżej) z dodatkiem opartym typu std::get. Więc zamiast std::get<0>(t) w poniższym przykładzie, możesz mieć std::get<int>(t).


dla C++ 11 std::make_pair pozwala to zrobić, a także std::make_tuple dla więcej niż dwóch przedmiotów.

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 zwróci dwa argumenty w std::pair. Elementy są dostępne pod numerem .first i .second.

Od ponad dwóch obiektów, musisz użyć 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 jest o zmiennej liczbie argumentów szablonu, który wybuduje krotki dowolnej liczby argumentów (z pewnymi ograniczeniami technicznymi oczywiście). Elementy mogą być dostępne przez indeks z std::get<INDEX>(tuple_object)

wewnątrz ciał pętlowych można łatwo alias obiektów, choć nadal trzeba używać .first lub std::get dla dla stanu pętli i aktualizować wyraz

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 
} 

Dla C++ 98 i C++ 03 Można jawnie nazwać typy std::pair. Nie ma standardowy sposób uogólniać to więcej niż dwóch rodzajów mimo:

for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) { 
    std::cout << p.second << std::endl; 
} 
+1

Jeśli robisz C++ 17, możesz nawet upuścić 'make_' i napisać' std :: pair (1, 1.0) '. –

+0

Owłosiona krotka biznes w stylu C++ 14 - wszystko dobrze (pewnie, przegłosowane), ale wygląda dziwacznie :) – mlvljr