Nel mio framework del compilatore (che verrà rilasciato Sometime Soon ™), si passano voci di informazioni come token in un oggetto del compilatore, quindi si chiama finalize
per indicare la fine del flusso.
Sarebbe male distruggere un oggetto senza chiamare finalize
, perché non svuoterebbe tutto il suo output. Tuttavia, il distruttore non può eseguire finalize
, perché può generare un'eccezione e allo stesso modo è errato chiedere finalize
per altri output se il parser è già in fase di interruzione.
Nel caso in cui tutti gli input siano già incapsulati da un altro oggetto, è piacevole passare l'input a un oggetto del compilatore rvalue.
pile< lexer, parser >(output_handler).pass(open_file("source.q"));
Senza un sostegno speciale, questo deve essere corretto perché finalize
non è sempre chiamato. L'interfaccia non dovrebbe permettere all'utente di fare una cosa del genere.
La prima cosa da fare è escludere il caso in cui finalize
non viene mai chiamato. L'esempio precedente è annullato se il prototipo è regolata con un lvalue ref-qualificazione come questo:
void pass(input_file f) & {
process_the_file();
}
Questo rende spazio per aggiungere un altro sovraccarico che finalizza correttamente l'oggetto. È abilitato per il rinnovo del valore, quindi viene selezionato solo se chiamato su un oggetto che sta scadendo.
void pass(input_file f) && {
pass(std::move(f)); // dispatch to lvalue case
finalize();
}
Ora l'utente quasi mai bisogno di preoccuparsi di ricordarsi di chiamare finalize
, poiché la maggior parte degli oggetti del compilatore sono in ultima analisi istanziati come provvisori.
Nota, questo genere di cose non è specifico per i membri qualificati. Qualsiasi funzione può avere sovraccarichi separati per t &
e t &&
. Il modo in cui pass
è in realtà attualmente implementata utilizza l'inoltro perfetto e poi fa marcia indietro per determinare la semantica corretta:
template< typename compiler, typename arg >
void pass(compiler && c, arg a) {
c.take_input(a);
if (! std::is_reference<compiler>::value) {
c.finalize();
}
}
Ci sono molti modi per affrontare il sovraccarico. In realtà, le funzioni dei membri non qualificate sono inusuali in non e si preoccupano della categoria (lvalue o rvalue) dell'oggetto su cui sono chiamate e non passano tali informazioni nella funzione. Qualsiasi parametro di funzione oltre l'implicito this
deve dire qualcosa sulla categoria del suo argomento.
Con i compilatori che lo supportano ora, mi aspetto di vedere presto un articolo o due sull'argomento. – chris
gcc l'ha appena implementato in 4.8.1, quindi non molte persone hanno ancora usato questa funzione. –
Fondamentalmente ogni volta che si desidera che gli utenti non creino oggetti permanenti di una classe, ma usino solo i provvisori, è possibile ottenere tale risultato rendendo le funzioni membro desiderate '&&'. –