For döngüsünde farklı türde iki değişken bildirmek mümkün müdür?


240

C ++ 'da bir for döngüsünün başlatma gövdesinde farklı türde iki değişken bildirmek mümkün müdür?

Örneğin:

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

iki tamsayıyı tanımlar. Başlatma gövdesinde inta ve a tanımlayabilir miyim char? Bu nasıl halledilebilir?


3
G ++ - 4.4 ( -std=c++0x) biçiminde mümkündür for(auto i=0, j=0.0; ..., ancak bu olasılık c ++ 0x metinleriyle çakışmak için g ++ - 4.5'te kaldırılmıştır.
rafak

Yanıtlar:


133

C ++ 17 : Evet! Yapısal bir bağlayıcı bildirim kullanmalısınız . Sözdizimi gcc ve clang'da yıllardır desteklenmektedir (gcc-7 ve clang-4.0'dan beri) ( clang canlı örneği ). Bu, aşağıdaki gibi bir paketi açmamızı sağlar:

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

Yukarıdakiler size verecektir:

  • int i ayarlanır 1
  • double f ayarlanır 1.0
  • std::string s ayarlanır "ab"

#include <tuple>Bu tür bir beyan için emin olun .

Bir türü adlandırmak istiyorsanız, tuplehepsini bende olduğu gibi yazarak içindeki tam türleri belirleyebilirsiniz std::string. Örneğin:

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

Bunun özel bir uygulaması bir harita üzerinde yineleme yapmak, anahtar ve değeri elde etmek,

std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
   // ...
}

Burada canlı bir örneğe bakın


C ++ 14 : C ++ 11 ile aynı işlemi yapabilirsiniz (aşağıda) tür tabanlı std::get. std::get<0>(t)Aşağıdaki örnek yerine , sahip olabilirsiniz std::get<int>(t).


C ++ 11 : ikiden fazla nesne için std::make_pairolduğu gibi bunu yapmanızı sağlar 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_pairiki argümanı a std::pair. Elemanlara .firstve ile erişilebilir .second.

İkiden fazla nesne için, bir 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_tupleherhangi bir sayıda argümanın bir demetini oluşturacak (elbette bazı teknik sınırlamalarla) varyasyonlu bir şablondur. Elemanlara indeks ilestd::get<INDEX>(tuple_object)

Döngü organları içinde, kolayca nesneleri takma, hala kullanımda gerek olsa .firstveya std::getdöngü koşulu ve güncelleme ifadesi için için

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 ve C ++ 03 a türlerini açıkça adlandırabilirsiniz std::pair. Ancak bunu ikiden fazla türe genelleştirmek için standart bir yol yoktur:

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

5
C ++ 17 yapıyorsanız, make_yazıp bırakabilirsiniz std::pair(1, 1.0).
Marc Glisse

Tüylü C ++ 14 tarzı tuple / çift iş - hepsi iyi (muhtemelen, upvoted), ama tuhaf görünüyor :)
mlvljr

3
Kısacası: Evet mümkün, ama güzel olmayacak.
Bazı programcı ahbap

Evet güzel değil, ama uyuşturucu! Kesinlikle tuple-ish bir zevk. :) Ama gerçekten C ++ döngüler için çok sezgisel olmayan sözdizimsel bir kalite ve nihayet Googled ne olduğunu anlamak için yarım saatten fazla baş ağrısı verdi ...
aderchox

@aderchox Yanlış anlaşılmayı netleştirebilirseniz cevabı güncelleyebilirim
Ryan Haining

276

Hayır - ama teknik olarak bir geçici çözüm var (zorunlu olmadığı sürece gerçekten kullanacağımdan değil):

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

3
Bu VS 2008'de derlenmez, ancak Comeau çevrimiçi ;-)
JRL

7
@JRL: Oh, VS2005 de yok. Yine başka bir uygunsuzluk özelliği VC ++ sanırım.
Georg Fritzsche

3
Eşdeğerini Perl'de yaptım. Gerçi, C ++ bir kod inceleme yoluyla böyle bir şey sinsice denemedim.
John

21
c ++ 11 ile varsayılan değerleri kullanarak bu örneği struct { int a=0; char b='a'; } s;
Ryan Haining

1
Bu cevap cevabın gereklerini yerine getiriyor, ancak okunabilirlik POV'sundan @ MK'yi tercih ediyorum. cevabı. MK'nin çözümü, kaşlı ayraçları ekleyerek kapsamı ele alır.
Trevor Boyd Smith

221

Mümkün değil, ancak şunları yapabilirsiniz:

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

Veya, ek parantezlerin kapsamını fve kullanımını açıkça sınırlayın i:

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

Bunun çok eski bir soru olduğunu biliyorum, ama ikinci örneğinizde olduğu gibi neden bazılarını etrafındaki ekstra parantezlerle yapacağını açıklayabilir misiniz?
Ford

13
@fizzisist, f ve i'nin kapsamını, kodun yalnızca kullanıldıkları bölümleriyle açıkça sınırlamak için @fizzisist.
MK.

1
@MK. Teşekkürler, bundan şüpheliydim. Bunu açıklamak için cevabınızı düzenledim.
Ford

Sadece bir soru: Neden böyle? : O
rohan-patel

Sanırım 'int a = 0, b = 4' gibi çalıştığını düşünüyorum. Olduğu söyleniyor, f ve i kapsamı muhtemelen bu isimlerin tekrar kullanılmasını önlemek için yararlı olacaktır (bu adil bir nedendir), ancak üretilen kod genellikle modern bir derleyicide aynı olacaktır (bu durumda).
Asu

14

Başlatmada birden çok tür bildiremezsiniz, ancak birden çok EG türüne atayabilirsiniz

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

Sadece kendi kapsamlarında beyan edin.


3

Bence en iyi yaklaşım xian'ın cevabı .

fakat...


# Döngü için iç içe

Bu yaklaşım kirli, ancak tüm sürümlerde çözülebilir.

bu yüzden onu makro fonksiyonlarda kullanıyorum.

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
    }

Ek 1.

Aynı zamanda kullanılabilir declare local variablesve 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.
    }

Ek 2.

İyi örnek: makro işlevli.

(En iyi yaklaşım bir for-loop-macro olduğu için kullanılamıyorsa)

#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-ifade hilesi

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

0Veya olarak başlatmak nullptristiyorsanız, bu numarayı kullanabilirsiniz.

ama sert okuma nedeniyle bunu tavsiye etmiyorum.

ve böcek gibi görünüyor.


Bazı insanların diğerlerinden ne kadar farklı düşündüklerini şaşırtmak asla bitmiyor. Böyle tuhaflıkları hiç düşünmezdim. İlginç fikirler.
Dr. Kişi Kişi II

1

"Bkz döngü içinde iki tip değişkenleri tanımlamak için bir yol var mı? " Döngüler için yuvalama birden yer aldığı başka bir yol. Georg'un "yapı hilesi" ne karşı diğer bir avantajı, (1) statik ve statik olmayan yerel değişkenlerin bir karışımına sahip olmanıza ve (2) oynatılamayan değişkenlere sahip olmanıza izin vermesidir. Dezavantajı, çok daha az okunabilir olması ve daha az verimli olabilmesidir.


-2

Bir makro tanımlayın:

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

Unutmayın, değişken kapsamlarınız da bu şekilde for döngüsü içinde olmayacaktır.


Kolayca kullanarak ayrı kapsamda makrosundaki kodu kaydırma tarafından bu sınırlamanın üstesinden olabilir {ve }.
Nathan Osman

4
Hayır yapamadı. Makroları döngü gövdesini sarmaz. Fazladan bir açılış ayracı ekleyebilir, ancak bu makroyu kullanırken "fazladan" bir kapanış ayracı gerektirir.
John

3
İlginç bir fikir, ama bunu düşünmeden önce diğer cevaplardan herhangi birini daha önce kullanacağım.
gregn3

-2

Ayrıca aşağıdaki gibi C ++ kullanabilirsiniz.

int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
  // your code
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.