2015-04-08 17 views
11

In realtà si tratta di due domande correlate.Stenografia per il ciclo - zucchero sintattico in C++ (11)

So che c'è una nuova sintassi in C++ 11 per la gamma a base for anse del modulo:

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

Prima domanda: come posso deduco in cui l'iterazione sono in questo ciclo? (Dire che voglio riempire un vettore con valore j alla posizione j).

Seconda domanda: volevo sapere se c'è anche qualche altro modo per scrivere un ciclo della forma

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

Trovo questo modo di scrivere è un po 'ingombrante, e lo faccio così spesso e Mi piacerebbe avere una sintassi più concisa per questo. Qualcosa sulla falsariga:

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

sarebbe grande.

Per entrambe le domande vorrei evitare di dover utilizzare librerie aggiuntive.

+2

Se tutto ciò che si desidera è * riempire un vettore con valore j alla posizione j * è possibile utilizzare [std :: iota()] (http://en.cppreference.com/w/cpp/algorithm/iota) –

+3

Una domanda alla volta, per favore. Quindi possiamo chiudere ciascuno come un duplicato della domanda preesistente che non hai cercato. :) –

+0

@Anton Thx per la iota! Non è tutto quello che voglio, ma certamente è bello saperlo. – dingalapadum

risposta

9

Per la prima domanda, la risposta è piuttosto semplice: se è necessario il conteggio dell'iterazione, non utilizzare il costrutto sintattico che astrae il numero di iterazioni. Basta usare un normale ciclo for e non quello basato sull'intervallo.

Per la seconda domanda, non credo che ci sia qualcosa attualmente nella libreria standard, ma è possibile utilizzare un boost::irange per esso:

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

ok. grazie. ma vorrei evitare di dover utilizzare librerie aggiuntive solo per questo. Modificherò la mia domanda. – dingalapadum

+5

@dingalapadum Ti risparmierai un mondo di dolore e reinvenzione ruota se non consideri Boost una "ulteriore lib". Trattalo come una "appendice della libreria standard". – Angew

+1

@Angew Anche se il boost di oggi è presente sulla maggior parte dei sistemi, rende la compilazione più lenta, e talvolta un po 'instabile, con il crescere del numero di dipendenze. Quindi è una scelta rispettabile per non volerlo usare. – Aracthor

18

Prima risposta: non lo fai. Hai usato un semplice costrutto per uno scopo semplice; avrai bisogno di qualcosa di più complicato se hai esigenze più complicate.

Seconda risposta: è possibile creare un tipo di iteratore che produce valori interi consecutivi e un tipo di "contenitore" che fornisce un intervallo di tali valori. Se non avete una buona ragione per farlo da soli, Boost ha such a thing:

#include <boost/range/irange.hpp> 

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

Utilizzare questa:

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

(. Boost è buono, ma non è universalmente accettata)

1

Se v è un vettore (o qualsiasi contenitore contiguo std), quindi

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

imposterà la voce ith sul valore i.

Un iteratore di uscita che conta è ragionevolmente facile da scrivere. Boost ha uno e ha un intervallo facile da generare di loro chiamato irange.

L'estrazione degli indici di un contenitore è relativamente semplice. Ho scritto una funzione chiamata indexes che può contenere un contenitore o un intervallo di numeri interi e produce iteratori di output casuali nell'intervallo in questione.

Che ti dà:

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

probabilmente c'è una funzione intervallo equivalente contenitore-to-indice in Boost.

Se avete bisogno di entrambi e non volete fare il lavoro, potete scrivere una cerniera.

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

dove zip prende due o più intervalli iterabili (o contenitori) e produce una vista intervallo su tuple iterator_traits<It>::reference s agli elementi.

Ecco l'iteratore di zip Boost: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html - le probabilità sono che ci sia una gamma di zip Boost che gestisce la sintassi come la precedente funzione zip.

3

Per la seconda domanda - se Boost è troppo pesante, si può sempre usare questa libreria:

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

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

Anche i doppi e altri tipi numerici sono supportati.

Ha altri strumenti di iterazione pironica ed è solo di intestazione.

0

Per la seconda domanda, se si utilizzano le ultime versioni di Visual Studio, di tipo 'se' quindi Tab, Tab, e Tab per riempire di valore init, step-up e così via.

2

Si può fare entrambe le cose con Boost.Range: http://boost.org/libs/range

Per brevità (e per rendere le cose un po ', dal boost::irange è stato già dimostrato in isolamento), ecco un codice di esempio dimostrando che queste funzionalità lavorano insieme:

// 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; 
} 

Esempio di output:

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

Per la seconda domanda:

c'è un altro modo, ma vorrei Non utilizzare o lo consiglio.Tuttavia, per impostare rapidamente un test si potrebbe scrivere:

se non si desidera utilizzare una biblioteca e si sta bene a fornire solo la parte superiore vincolata della gamma è possibile scrivere:

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

Questo creerà un vettore booleano di dimensione 10, con valori non inizializzati. Effettuare il rincorsa attraverso questi valori unitializzati usando i (quindi lo non usa i) stamperà 10 volte "x".

+0

Interessante. cosa sarà 'io' essere in questo caso? Questo crea un nuovo vettore di bool di dimensione 10? O cosa succede esattamente qui? – dingalapadum

+0

Sì, crea un vettore di dimensione 10, è assolutamente eccessivo lo scopo, ma possibile. ;) 'i' saranno i valori booleani non inizializzati del vettore. – Stuck

+0

Ok. una specie di loop costoso ... Mi piacerebbe molto suvviare perché lo trovo creativo ... poi ancora, non lo userei mai o lo consiglio a nessuno ... inoltre, non è come una stenografia o uno zucchero sintattico . Tuttavia, se metti quei dettagli che hai menzionato nel post e chiarisci gli aspetti che sono disposto a revocare come ricompensa per lo sforzo. – dingalapadum

Problemi correlati