2012-03-01 12 views
9

È a mia conoscenza che i modelli di espressione si interromperanno su ranged based per in C++ 11, poiché for (auto x : expr) contiene un numero implicito auto&& __range = expr e ciò comporterà riferimenti penzolanti.Modelli di espressione e basati sulla frequenza in C++ 11

C'è un modo per creare classi di modelli di espressioni in modo che si comportino correttamente con ranged based o, per lo meno, generino un errore di compilazione?

Fondamentalmente, vorrei evitare la possibilità che i modelli di espressioni vengano compilati correttamente ma non riescano in fase di esecuzione a causa di riferimenti penzolanti. Non mi interessa dover avvolgere i modelli di espressioni in qualcosa prima di usarli in un campo basato su, a patto che non vi siano errori di run-time silenziosi se l'utente dimentica di avvolgere i modelli di espressione.

+1

L''auto &&' nel ciclo 'for' basato sull'intervallo potrebbe davvero rivelarsi qualcosa da sparare facilmente nel piede - Non ho ancora capito bene quali tipi di intervallo sono esattamente interessati e perché (riferimenti lvalue a non-const: pericoloso, non-riferimento: non problematico, ???). – Philipp

+1

@Philipp: non esiste un "tipo di intervallo". Esistono semplicemente tipi conformi al "concetto" di intervallo. Nello specifico, ci sono una coppia di override 'begin/end' che restituiscono gli iteratori di input. –

+1

Suppongo che la risposta sia assicurarsi che i modelli di espressione non siano conformi al "concetto" di intervallo, cioè non hanno 'begin' e' end'. – Clinton

risposta

2

Ci sono alcune opzioni a cui riesco a pensare, ciascuna con la propria bruttezza.

Un'opzione ovvia è utilizzare i puntatori (probabilmente unique_ptr) anziché i riferimenti. Naturalmente, affinché funzioni, richiede l'allocazione dall'heap o dagli allocatori personalizzati. Penso che con un buon allocatore, questo approccio abbia dei meriti. Poi di nuovo, l'overloading dell'operatore diventerebbe semplicemente cattivo.

Un altro approccio è quello di memorizzare sottoespressioni per valore anziché per riferimento const. L'efficienza di questo approccio è molto dipendente dal compilatore, ma dal momento che si tratta fondamentalmente di un mucchio di provvisori, immagino che i compilatori moderni possano ottimizzare le copie (o almeno, molte delle copie).

L'ultimo approccio consente di mantenere la stessa struttura sul codice, ma costringe l'utente a valutare l'espressione. È necessario disporre di un solo tipo iterabile, che è il tipo sottostante dell'espressione (ad esempio, std::vector<int>). Nessuna delle classi di espressioni deve avere i metodi begin e end definiti per loro, ma dovrebbe essere convertibile nel tipo sottostante. In questo modo, il codice come for(auto x : expr) non riuscirà in fase di compilazione (poiché expr non è iterabile), ma la scrittura di for(auto x : static_cast<vector<int>>(expr)) funziona perché l'espressione è già valutata.

Se si desidera utilizzare i cicli basati su intervalli per implementare le operazioni del modello di espressione, è possibile fornire metodi protetti o protetti da begin e end nelle classi del modello di espressione. Assicurati solo che ogni classe template possa accedere ai metodi begin e end delle altre classi template. Va bene in questo contesto poiché il modello di espressione è un parametro della funzione, quindi non dovrai preoccuparti di far ciondolare i riferimenti quando scrivi il ciclo all'interno di quella funzione.

6

Generalmente non c'è niente che tu possa fare al riguardo. Se assegni un'espressione come intervallo, deve risolversi in qualcosa che sarà valido dopo l'inizializzazione dell'istruzione for. E non c'è modo di rilevare in fase di compilazione che qualsiasi tipo particolare sia stato dedotto da auto.

Sarebbe meglio rendere il sistema di espressione più basato su spostamenti, in modo che non debba contenere riferimenti. Ciò produrrà risultati molto più sicuri con auto rispetto al tentativo di memorizzare riferimenti a cose potenzialmente morte. Se la copia per tipi non mobili ti disturba, allora vivi semplicemente con essa.

+2

Questo non risolve il problema. Il ciclo for-range basato sull'intervallo contiene un implicito 'auto && __ range = listOfInt;', che potrebbe causare problemi se 'listOfInt' fosse effettivamente un valore di qualche classe template di espressioni. –

+0

@RichardSmith: È vero, penso che in quel caso l'unica cosa che si potrebbe fare è introdurre un cast esplicito o una nuova variabile automatica. – Philipp

Problemi correlati