2013-07-22 19 views
29

Supponiamo che stiate scrivendo una funzione che accetta uno std::initializer_list chiamato list e che la funzione richiede l'accesso casuale agli elementi di list. Sarebbe conveniente scrivere list[i] anziché list.begin()[i]. Quindi, perché std::initializer_list non fornisce una definizione di operator[]?Perché `std :: initializer_list` non fornisce un operatore di pedici?

Non riesco a pensare a casi in cui un operator[] restituisce const T& non sarebbe ben definito. L'efficienza non sembra essere il problema qui, dal momento che std::initializer_list<T>::iterator è con alias a const T*, che è chiaramente un iteratore ad accesso casuale.

+1

Indovino perché il suo caso d'uso principale deve essere una lista che viene elaborata in sequenza. – PlasmaHH

+2

Un caso d'uso comune è per un costruttore che assegna un blocco di memoria e costruisce gli elementi nel blocco usando 'allocator.construct (p, v)'.Mentre la lista è ancora processata in modo sequenziale, il ciclo for esterno ha già un contatore che si presta alla sintassi 'operator []'. –

+0

@ void-pointer Non sareste normalmente * copiati * in queste circostanze? In questo modo non hai bisogno di un ciclo e in genere eviterei comunque un ciclo esplicito. La domanda è ancora valida, però. –

risposta

9

Secondo Bjarne Stroustrup nel paragrafo 17.3.4.2 (p 497). Di The C++ Programming Language, 4 ° Edizione:

Purtroppo, initializer_list non fornisce subscripting.

Nessun ulteriore motivo è dato.

mia ipotesi è che si tratta di uno di questi motivi:

  1. è una dimenticanza, o
  2. perché la classe initializer_list è realizzato con un array e che avrebbe dovuto fare il controllo dei limiti di fornire accesso sicuro , potrebbe facilmente essere utilizzata non sicuro se era previsto che l'interfaccia, o
  3. sia coerente con l'algoritmi std iterazione paradigma, o
  4. perché initializer_lists sono, per loro natura, ad-hoc, non c'è più spazio per errore indirizzandoli direttamente

2 e 4 tipo di suono debole. come fa 3. Scommetto su 1.

+1

Basta leggere il libro di Bjarne oggi, e cercavo ragioni ... – lpapp

2

E 'in effetti un po' fastidioso, non avendo parentesi operatore quadrato per std :: initializer_list, come la necessità di un accesso diretto casuale per un indice specifico è uno scenario ragionevole.

Tuttavia, questa capacità può essere aggiunto con un certo codice semplice:

// the class _init_list_with_square_brackets provides [] for initializer_list 
template<class T> 
struct _init_list_with_square_brackets { 
    const std::initializer_list<T>& list; 
    _init_list_with_square_brackets(const std::initializer_list<T>& _list): list(_list) {} 
    T operator[](unsigned int index) { 
     return *(list.begin() + index); 
    } 
}; 

// a function, with the short name _ (underscore) for creating 
// the _init_list_with_square_brackets out of a "regular" std::initializer_list 
template<class T> 
_init_list_with_square_brackets<T> _(const std::initializer_list<T>& list) { 
    return _init_list_with_square_brackets<T>(list); 
} 

ora abbiamo una nuova funzione globale chiamato _ (trattino basso), che probabilmente non è un buon nome per il metodo di un C globale ++, a meno che non voglio creare una utility lib di tipo "undescore" per C++, che avrà il proprio spazio dei nomi, sovraccaricando la funzione _ per tutti gli altri usi utili.

La nuova _ funzione può essere utilizzata ora come questo:

void f(std::initializer_list<int> list) { 
    cout << _(list)[2]; // subscript-like syntax for std::initializer_list! 
} 

int main() { 
    f({1,2,3}); // prints: 3 
    cout << _({1,2,3})[2]; // works also, prints: 3 
    return 0; 
} 

E 'da notare che la soluzione fornita di cui sopra non è un buon affare in termini di prestazioni se si esegue nel corso di molti elementi di std: : initializer_list, come oggetto temporaneo del tipo suggerito sopra _init_list_with_square_brackets viene creato ripetutamente. Che, naturalmente, fa sorgere la meraviglia perché questo non è stato fornito dallo standard stesso.

+0

Questo è bello. Un'alternativa, il dirottamento del commento di @ Yakk sulla domanda, è "auto mylist = list.begin()" e poi mylist [n] funziona. –

+4

Se vedessi la sintassi in un codice, sarei immediatamente "wtf". Sarei senza tracce che '_' è in realtà un id, meno denotando una funzione. Come rly, "wtf". Probabilmente alla fine lo capirò (funziona "go to definition" per un id chiamato '_' ??), ma ciò non farà nulla per alleviare le mie intense, rapide e ripetute menzioni della famiglia del coder che ha scritto quella. Il mio consiglio è di andare su 'list.begin() [i]'. Mi dispiace di downvotare perché è un trucco interessante, dal punto di vista della lingua, ma in pratica si ritorcerà contro. – bolov

+0

Immagino che in realtà tu voglia restituire un 'cons T &' invece di una copia. – MikeMB

Problemi correlati