2015-06-03 14 views
6

Stavo cercando di stampare un array 2D utilizzando for_each e il ciclo basato su for.for_each & ranged base per array 2D

Il mio programma va in questo modo: -

#include <iostream> 
#include <algorithm> 
using namespace std; 
int main() 
{ 
    int a[3][3]={{1,2,3},{4,5,6},{7,8,9}}; 
    //for_each (begin(a), end(a), [] (int x) { cout<<x<<" ";}); this code throws error 

    for_each (begin(a[0]), end(a[2]), [] (int x) { cout<<x<<" ";}); //this code works well, why ? 

    cout<<endl; 

    for (auto &row: a) // without & for row, error is thrown 
    { 
    for (auto x:row) // no & needed for x, why ? 
    { 
     cout<<x<<" "; 
    } 
    } 
    return 0; 
} 

Perché i miei primi for_each errori di tiro e perché è & simbolo necessario per la fila? Qual è il suo tipo? row è un puntatore?

risposta

4
for_each (begin(a), end(a), [] (int x) { cout<<x<<" ";}); 

begin(a) produce un int(*)[3] (puntatore a matrice di dimensioni [3]), e deferenziandolo produce un int(&)[3], mentre l'espressione lambda aspetta un argomento int.

for_each (begin(a[0]), end(a[2]), [] (int x) { cout<<x<<" ";}); 

begin(a[0]) produce un int* che punta al primo elemento nella prima fila di a e end(a[2]) produce un int* punta a uno dopo l'ultimo elemento nell'ultima fila di a, quindi tutto funziona.


Ora per la parte basata su intervallo for.

Se si rimuove il & dalla riga for (auto& row : a), l'errore si verifica effettivamente nella seguente riga for(auto x : row). Questo è dovuto al modo in cui è specificato lo range-based for. La clausola pertinente al caso d'uso è

Se __range è un array, quindi begin_expr è __range e end_expr è (__range + __bound), dove __bound è il numero di elementi nella matrice (se l'array ha dimensione sconosciuta o è di un tipo incompleto, il programma è mal-formato)

Hereon io sarò riferisco alle identificatori citati nel Spiegazione sezione della pagina collegata.


Consideriamo il caso for (auto& row : a):

__range si deduce come int(&)[3][3] (riferimento alla matrice di dimensioni [3] [3]). __begin viene quindi dedotto come int(*)[3] (puntatore a matrice di dimensioni [3]) poiché il tipo di __range decade in un puntatore alla prima riga dell'array 2D. range_expression è auto& row, quindi row viene dedotto come int(&)[3] (riferimento alla matrice di dimensioni [3]).

Successivamente, lo stesso processo viene ripetuto per il numero interno for. In questo caso, __range è int(&)[3] e si applica la clausola dell'array I citata sopra; il restante processo di deduzione del tipo è simile a quello che ho descritto sopra.

__range = int(&)[3] 
__begin = int* 
x  = int 

Consideriamo ora il caso for (auto row : a):

__range, __begin e __end sono tutti dedurre lo stesso. La differenza cruciale in questo caso è range_expressionauto row, che causa il decadimento del tipo int(*)[3] che __begin è stato dedotto come. Ciò significa cheviene dedotto come int * e nessuna delle 3 clausole in cui è descritta la determinazione di begin_expr/end_expr gestisce un puntatore non elaborato. Ciò si traduce in un errore di compilazione all'interno del ciclo nidificato for.

+0

Capo Thnx! Questa spiegazione è stata molto chiara e concisa! – Anwesha

3

a è un array bidimensionale - un int[][] se lo si desidera.

Ciò significa che quando si itera a, si sta iterando solo la prima dimensione di array - a[0] fino a a[2]. a[0] è ancora un array, il che spiega il motivo per cui il tuo primo for_each potrebbe produrre un errore: il lambda che hai fornito si aspetta un int ma verrà passato un int*.

Il riferimento (simbolo &) è necessario nel primo intervallo per lo stesso motivo. Senza il & il compilatore tenta di copiare gli oggetti nella prima dimensione, ma questi sono gli array stessi e non è possibile copiare un array in base al valore in C++.

Il secondo intervallo per non ha bisogno di un riferimento perché sta iterando la seconda dimensione dell'array, che consiste in semplici inte.