La motivazione centrale per l'introduzione di una sentinella è che ci sono molte operazioni di iteratore che sono supportate ma di solito non sono mai necessarie per l'iteratore finale end()
. Ad esempio, non vi è quasi alcun punto nel dereferenziamento tramite lo *end()
, nell'incrementarlo tramite ++end()
e così via (*).
Al contrario, l'utilizzo principale di end()
consiste semplicemente nel confrontarlo con un iteratore it
per segnalare se it
è alla fine della cosa che viene semplicemente iterata. E, come sempre nella programmazione, requisiti diversi e diverse applicazioni suggeriscono un nuovo tipo.
La libreria range-v3 trasforma questa osservazione in un'ipotesi (che è implementata attraverso un concetto): introduce un nuovo tipo per end()
e richiede solo che sia uguaglianza-paragonabile al corrispondente iteratore - ma non richiede le solite operazioni di iteratore). Questo nuovo tipo di end()
è chiamato sentinella.
Il vantaggio principale qui è l'astrazione acquisita e una migliore separazione delle preoccupazioni, in base alla quale il compilatore è eventualmente in grado di eseguire una migliore ottimizzazione. Nel codice, l'idea di base è questa (questo è solo per la spiegazione e non ha nulla a che fare con la libreria gamma-v3):
struct my_iterator; //some iterator
struct my_sentinel
{
bool is_at_end(my_iterator it) const
{
//here implement the logic when the iterator is at the end
}
};
auto operator==(my_iterator it, my_sentinel s) //also for (my_sentinel s, my_iterator it)
{
return s.is_at_end(it);
}
Vedi l'astrazione? Ora, è possibile realizzare qualsiasi controllo che si desidera nella funzione is_at_end
, ad esempio:
- fermata mai (ottenere una gamma infinita)
- fermata dopo
N
incrementi (per ottenere una gamma contati)
- arresto quando una
\0
viene rilevato, ovvero *it = '\0'
(per il loop su stringhe a C)
- fermarsi quando è 12'o orologio (per pranzare) e così via.
Inoltre, riguardo alle prestazioni, si è in grado di fare uso di tempo-informazione compilazione nel controllo (ad esempio, pensare al N
sopra come parametro in fase di compilazione). In questo caso, il compilatore potrebbe essere in grado di ottimizzare meglio il codice.
(*) Si noti che questo non significa che in generale non è utile per questo tipo di operazioni.Ad esempio, --end()
può essere utile in alcuni luoghi, vedi ad es. this question. Tuttavia, è apparentemente possibile implementare la libreria standard senza questi - questo è ciò che ha fatto la libreria range-v3.
cos'è una gamma zip? – Walter
@walter ha aggiunto la nota – Yakk
Hmm. Ma un iteratore zip non può essere un RandomAccessIterator, poiché il suo 'reference' non è identico a' value_type &'. Quindi alcuni algoritmi standard potrebbe non funzionare (come hai detto tu stesso (http://stackoverflow.com/a/32871002/1023390).) Allora, a cosa serve – Walter