2015-04-08 7 views
11

Eigentlich sind das zwei verwandte Fragen.Kürzel für for-Schleife - syntaktischer Zucker in C++ (11)

Ich weiß, dass es eine neue Syntax ist in C++ 11 für bereichsbasierte for Schleifen der Form:

//v is some container 
for (auto &i: v){ 
    // Do something with i 
} 

Erste Frage: Wie kann ich ableiten, welche Iteration ich in dieser Schleife bin? (Angenommen, ich möchte einen Vektor mit dem Wert j an Position j füllen).

Zweite Frage: Ich wollte wissen, ob es auch eine andere Möglichkeit ist es, eine Schleife der Form

for (int i=0; i<100; i++) { ... } 

ich diesen Weg finden, schreiben Sie es ein bisschen umständlich zu schreiben, und ich tue dies so oft und Ich hätte gerne eine präzisere Syntax dafür. Etwas entlang der Linien:

for(i in [0..99]){ ... } 

wäre toll.

Für beide Fragen möchte ich vermeiden, zusätzliche Bibliotheken zu verwenden.

+2

Wenn Sie nur einen Vektor mit dem Wert j an der Position j * füllen möchten, können Sie [std :: iota()] verwenden (http://en.cppreference.com/w/cpp/algorithm/iota) –

+3

Eine Frage nach der anderen, bitte. Dann können wir jedes als Duplikat der bereits vorhandenen Frage schließen, nach der Sie nicht gesucht haben. :) –

+0

@Anton Thx für das Iota! Es ist nicht _all_ ich will, aber es ist sicherlich gut zu wissen. – dingalapadum

Antwort

9

Für die erste Frage ist die Antwort ziemlich einfach: Wenn Sie die Iterationszählung benötigen, verwenden Sie nicht das syntaktische Konstrukt, das die Iterationszahl abstrahiert. Verwenden Sie einfach eine normale for-Schleife und nicht die bereichsbasierte.

Für die zweite Frage, ich glaube nicht, dass es etwas Zeit in der Standard-Bibliothek, aber man konnte ein boost::irange dafür verwenden:

for (int i : boost::irange(0, 100)) 
+0

ok. Danke. aber ich möchte vermeiden, zusätzliche libs nur dafür zu verwenden. Ich werde meine Frage bearbeiten. – dingalapadum

+5

@dingalapadum Wenn du Boost nicht als "zusätzliche Lib" betrachtest, ersparst du dir eine Welt der Schmerz- und Radneubildung. Behandeln Sie es einfach als "Standardbibliothekszusatz". – Angew

+1

@Angew Auch wenn der Boost heute auf den meisten Systemen vorhanden ist, wird die Kompilierung langsamer und manchmal ein wenig instabil, wenn die Abhängigkeitszahl steigt. Es ist also eine respektable Wahl, es nicht benutzen zu wollen. – Aracthor

18

Erste Antwort: Sie dies nicht tun. Sie haben ein einfaches Konstrukt für einen einfachen Zweck verwendet; Sie werden etwas komplizierteres brauchen, wenn Sie komplexere Bedürfnisse haben.

Zweite Antwort: Sie könnten einen Iterator-Typ erstellen, der aufeinanderfolgende Integer-Werte liefert, und einen "Container" -Typ, der einen Bereich von diesen ergibt. Es sei denn, Sie haben einen guten Grund, es selbst zu tun, Boost-hat such a thing:

#include <boost/range/irange.hpp> 

for (int i : boost::irange(0,100)) { 
    // i goes from 0 to 99 inclusive 
} 
10

verwenden:

size_t pos = 0; 
for (auto& i : v) { 
    i = pos; 
    ++pos; 
} 

(. Boost ist gut, aber es ist nicht allgemein akzeptiert)

1

Wenn v ist ein Vektor (oder irgendein zusammenhängender Behälter std), dann

for(auto& x : v) { 
    size_t i = &x-v.data(); 
    x = i; 
} 

setzt den i-ten Eintrag auf den Wert i.

Ein Ausgabe-Iterator, der zählt, ist relativ einfach zu schreiben. Boost hat einen und hat einen einfach zu generierenden Bereich von ihnen genannt irange.

Das Extrahieren der Indizes eines Containers ist relativ einfach. Ich habe eine Funktion namens indexes geschrieben, die einen Container oder einen Bereich von ganzen Zahlen nehmen kann und zufällige Ausgabe-Iteratoren über den betreffenden Bereich erzeugt.

Das gibt Ihnen:

for (size_t i : indexes(v)) { 
    v[i] = i; 
} 

Es ist wahrscheinlich eine äquivalente Container-to-Indexbereich Funktion in kurbeln.

Wenn Sie beide brauchen, und Sie nicht die Arbeit machen wollen, können Sie einen Reißverschluss schreiben.

for(auto z : zip(v, indexes(v))) { 
    auto& x = std::get<0>(z); 
    size_t i = std::get<1>(z); 
    x = i; 
} 

wo zip nimmt zwei oder mehr iterable Bereiche (oder Behälter) und erzeugt eine Reihe von Tupeln Blick auf iterator_traits<It>::reference s auf die Elemente.

Hier ist Boost Zip Iterator: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html - Chancen gibt es einen Boost Zip-Bereich, der Syntax wie die obige zip Funktion behandelt.

3

Für die zweite Frage - wenn Boost zu schwer ist, können Sie immer diese Bibliothek verwenden:

for(auto i : range(10, 15)) { cout << i << '\n'; } druckt 10 11 12 13 14

for(auto i : range(20, 30, 2)) { cout << i << '\n'; } druckt 20 22 24 26 28

Doppel und andere numerische Typen werden ebenfalls unterstützt.

Es hat andere Pythonic Iteration Tools und ist nur Header-Header.

0

Für die zweite Frage, ob Sie die neuesten Versionen von Visual Studio verwenden, geben Sie 'wenn' dann Tab, Tab und Tab in init Wert, Step-up zu füllen und so weiter.

2

Sie können mit Boost.Range diese beiden Dinge tun: http://boost.org/libs/range

Der Kürze halber (und etwas aufzupeppen ein wenig, da boost::irange bereits isoliert demonstriert wurde), hier ist ein Beispielcode, der diese Funktionen zusammen arbeiten zeigt:

// boost::adaptors::indexed 
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html 
#include <boost/range/adaptor/indexed.hpp> 

// boost::irange 
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html 
#include <boost/range/irange.hpp> 

#include <iostream> 
#include <vector> 

int main() 
{ 
    std::vector<int> input{11, 22, 33, 44, 55}; 
    std::cout << "boost::adaptors::indexed" << '\n'; 
    for (const auto & element : input | boost::adaptors::indexed()) 
    { 
     std::cout << "Value = " << element.value() 
        << " Index = " << element.index() 
        << '\n'; 
    } 

    endl(std::cout); 

    std::cout << "boost::irange" << '\n'; 
    for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100)) 
    { 
     std::cout << "Value = " << element.value() 
        << " Index = " << element.index() 
        << '\n'; 
    } 

    return 0; 
} 

Beispielausgabe:

boost::adaptors::indexed 
Value = 11 Index = 0 
Value = 22 Index = 1 
Value = 33 Index = 2 
Value = 44 Index = 3 
Value = 55 Index = 4 

boost::irange 
Value = 0 Index = 100 
Value = 1 Index = 101 
Value = 2 Index = 102 
Value = 3 Index = 103 
Value = 4 Index = 104 
1

Für die zweite Frage:

Es gibt einen anderen Weg, aber ich würde nicht benutzen oder es empfehlen.Doch für schnell einen Test einrichten könnten Sie schreiben:

wenn Sie nicht über eine Bibliothek verwenden möchten, und Sie sind gut mit nur den oberen Bereitstellung des Bereichs gebunden sind, können Sie schreiben:

for (auto i:vector<bool>(10)) { 
    cout << "x"; 
} 

Diese erstellt einen booleschen Vektor der Größe 10 mit nicht initialisierten Werten. Durchlaufen Sie diese vereinheitlichten Werte unter Verwendung von i (tun Sie auch nicht Verwendung i) es wird 10 mal "x" drucken.

+0

Interessant. Was wird "ich" in diesem Fall sein? Erstellt dies einen neuen Vektor von Bools der Größe 10? Oder was genau passiert hier? – dingalapadum

+0

Ja, es schafft einen Vektor der Größe 10, ist absolut überkilling den Zweck, aber möglich. ;) "i" sind die nicht initialisierten booleschen Werte des Vektors. – Stuck

+0

Ok. eine Art teure Schleife ... Ich würde es wirklich gerne aufwerten, weil ich es kreativ finde ... dann würde ich es nie benutzen oder jedem empfehlen ... auch nicht wie eine Kurzschrift oder syntaktischer Zucker . Trotzdem, wenn Sie die Details, die Sie erwähnt haben, in die Post schreiben und die Nachteile erklären, die ich als Belohnung für die Mühe aufzählen möchte. – dingalapadum

Verwandte Themen