2013-04-09 9 views
17

V'è una serie basata su ciclo for con la sintassi:Basato su intervallo per il loop su un array dinamico?

for(auto& i : array) 

Funziona con le matrici costanti, ma non con quelli dinamici basati puntatore, come

int *array = new int[size]; 
for(auto& i : array) 
    cout<< i << endl; 

Dà errori e gli avvertimenti circa il fallimento di sostituzione, ad esempio:

Error] C:\Users\Siegfred\Documents\C-Free\Temp\Untitled2.cpp:16:16: error: no matching function for call to 'begin(int*&)'

Come si utilizza questa nuova sintassi con gli array dinamici?

+2

cosa gli errori dicono? Almeno post ** uno ** errore – Default

+1

si chiama range-based per loop e SO e Google hanno tonnellate di esempi – stijn

+0

[Errore] C: \ Users \ Siegfred \ Documents \ C-Free \ Temp \ Untitled2.cpp: 16: 16: errore: nessuna funzione di corrispondenza per la chiamata a 'begin (int * &)' –

risposta

19

Per usufruire del gamma-based per-loop è necessario fornire sia begin() e end() funzioni membro o sovraccaricare il non membro begin() e end() funzioni. In quest'ultimo caso, si può avvolgere la vostra gamma in un std::pair e sovraccarichi begin() e end() per chi:

namespace std { 
     template <typename T> T* begin(std::pair<T*, T*> const& p) 
     { return p.first; } 
     template <typename T> T* end(std::pair<T*, T*> const& p) 
     { return p.second; } 
    } 

Ora è possibile utilizzare il ciclo for in questo modo:

for (auto&& i : std::make_pair(array, array + size)) 
     cout << i << endl; 

nota, che le funzioni non membro begin() e end() devono essere sovraccaricate nello spazio dei nomi std qui, poiché lo pair risiede anche nello spazio nomi std. Se non hai voglia di manomettere lo spazio dei nomi standard, puoi semplicemente creare la tua piccola classe di coppia e sovraccaricare lo begin() e lo end() nel tuo spazio dei nomi.

Oppure, creare un sottile involucro intorno al vostro array allocato in modo dinamico e fornire begin() e end() membri funzioni:

template <typename T> 
    struct wrapped_array { 
     wrapped_array(T* first, T* last) : begin_ {first}, end_ {last} {} 
     wrapped_array(T* first, std::ptrdiff_t size) 
      : wrapped_array {first, first + size} {} 

     T* begin() const noexcept { return begin_; } 
     T* end() const noexcept { return end_; } 

     T* begin_; 
     T* end_; 
    }; 

    template <typename T> 
    wrapped_array<T> wrap_array(T* first, std::ptrdiff_t size) noexcept 
    { return {first, size}; } 

e il vostro sito chiamata simile a questo:

for (auto&& i : wrap_array(array, size)) 
     std::cout << i << std::endl; 

Example

16

Non è possibile utilizzare range-for-loop con matrici allocate dinamicamente, poiché il compilatore non può dedurre l'inizio e la fine di questo array. È necessario utilizzare sempre i contenitori anziché, ad esempio std::vector.

std::vector<int> v(size); 
for(const auto& elem: v) 
    // do something 
+0

@Zoidberg, modificato, grazie :) – soon

+1

beh, ha funzionato! non ho mai saputo che il C++ sarebbe sicuro per questo tipo, venivo da C, quindi mi sono abituato a manipolare allo stesso modo array dinamici e costanti. –

+0

@MauriceRodriguez Bene, * C * ha questa differenza tra array e puntatori esattamente allo stesso modo. Ad esempio 'sizeof (array)' restituisce anche cose completamente diverse in * C *, a seconda che si tratti di 'int * array = malloc (N * sizeof (int));' or 'int array [N];'. Quindi è solo perché * C * ha reso più facile per te * erroneamente * ignorare questa differenza, non che questa differenza non fosse presente. –

8

Non è possibile eseguire un ciclo basato su una gamma di array allocato dinamicamente, perché tutto quello che hai è un puntatore al primo elemento. Non ci sono informazioni riguardo alle sue dimensioni che il compilatore può usare per eseguire il ciclo. La soluzione idiomatica C++ sarebbe quella di sostituire l'array allocato dinamicamente da un std::vector:

std::vector<int> arr(size); 
for(const auto& i : arr) 
    std::cout<< i << std::endl; 

Una gamma basati per ciclo funziona per std::array oggetti. Bisogna guardare oltre l'istanza array (arr), non il tipo (array):

std::array<int,10> arr; 
for(const auto& i : arr) 
    std::cout<< i << std::endl; 
+1

Si può già range-'for' su un array assegnato automaticamente, senza bisogno di aggiungere la classe wrapper solo per questo. 'int a [] {1, 2, 3}; for (auto it: a) std :: cout << it << ''; 'Ogni conteggio di elementi crea un tipo distinto per il quale' end' può essere dedotto durante la compilazione del ciclo. –

-1

consultare questa pagina http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer e trovare il capitolo "non membro begin() e la fine()". Questo potrebbe essere ciò che vuoi ottenere.

+0

È possibile collegare direttamente a quel capitolo con l'ancoraggio #beginend, quindi [come questo] (http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer#beginend). – Default

+2

Dovresti provare ad aggiungere il contenuto di ciò che vuoi che l'utente legga, dato che [le risposte al solo link sono in qualche modo scoraggiate] (http://meta.stackexchange.com/questions/8231/are-answers-that-just-taintain -links-altrove-davvero-good-risposte). – Default

+0

"Questo potrebbe essere quello che vuoi ottenere." No, non può. Richiederebbe in qualche modo di dedurre la dimensione/ultimo elemento per una matrice dinamica data solo un'istanza del suo tipo generico, il che non è possibile ... e dovrebbe essere ovvio dal fatto che tali funzioni non sono già fornite, per questo ragione esatta –