per iterare su un flusso di input, che di solito usare un std::istream_iterator
in questo modo:ciclo Gamma basati su un flusso di input
typedef std::istream_iterator<std::string> input_iterator;
std::ifstream file("myfile");
for (input_iterator i(file); i != input_iterator(); i++) {
// Here, *i denotes each element extracted from the file
}
Sarebbe bello se potessimo utilizzare la gamma a base di for
dichiarazione scorrere su flussi di input. Tuttavia, per oggetti di tipo classe, gamma-based for
richiede l'oggetto da avere begin()
e end()
funzioni membro (§6.5.4, enfasi grassetto aggiunto):
if
_RangeT
is an array type, begin-expr and end-expr are__range
and__range + __bound
, respectively, where__bound
is the array bound. If_RangeT
is an array of unknown size or an array of incomplete type, the program is ill-formed;if
_RangeT
is a class type, the unqualified-idsbegin
andend
are looked up in the scope of class_RangeT
as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, begin-expr and end-expr are__range.begin()
and__range.end()
, respectively;otherwise, begin-expr and end-expr are
begin(__range)
andend(__range)
, respectively, wherebegin
andend
are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespacestd
is an associated namespace.
I flussi di ingresso non hanno queste funzioni membro (non sono contenitori) e pertanto for
basato su intervallo non funzionerà su di essi. Ciò ha comunque senso poiché è necessario un modo per specificare il tipo da estrarre (std::string
nel caso precedente).
Ma se sappiamo quello che vogliamo estrarre, è possibile definire le nostre proprie begin()
e end()
funzioni (forse specializzazioni o sovraccarichi di std::begin()
e std::end()
) per l'input flussi tale che sarebbero stati trovati da accesso ricerca membro della classe come descritto sopra?
Non è chiaro (almeno per me) da §6.5.4 se le funzioni verranno cercate con ricerca dipendente dall'argomento se la precedente ricerca fallisce. Un'altra cosa da considerare è che std::ios_base
e i suoi derivati hanno già un membro chiamato end
che è una bandiera per la ricerca.
Ecco il risultato desiderato:
std::ifstream file("myfile");
for (const std::string& str : file) {
// Here, str denotes each element extracted from the file
}
Oppure:
std::ifstream file("myfile");
for (auto i = begin(file); i != end(file); i++) {
// Here, *i denotes each element extracted from the file
}
È solo per me, o è piuttosto poco chiaro dalle specifiche? Sembra che 'std :: begin()' e 'std :: end()' vengano trovati solo se '_RangeT' non è di tipo array o classe. –
Sì, non è la migliore espressione, ma penso che tu voglia leggerla come "se è una classe E ha .begin e .end poi userà quelli ... altrimenti", cioè puoi fornire le funzioni libere . –
"*' begin' e 'end' sono ricercati nell'ambito della classe _RangeT ... e se ** uno ... trova almeno una dichiarazione **,' begin-expr' e 'end-expr' sono '__range.begin()' e '__range.end()' * "- poiché' std :: ios_base :: end' esiste (e quindi 'std :: ifstream :: end' sarà trovato) il gioco è attivo . '.begin()' non verrà trovato, e '.end()' sarà un errore di sintassi. –