Domanda

Quali sono gli esempi più interessanti di metaprogrammazione che hai visto in C++?
Quali sono alcuni usi pratici della metaprogrammazione che hai visto in C++?

È stato utile?

Soluzione

Personalmente, penso Boost.Spirit è un esempio piuttosto sorprendente di meta-programmazione. È un generatore di parser completo che ti permette di esprimere grammatiche usando la sintassi C ++.

Altri suggerimenti

L'uso più pratico della meta-programmazione è trasformare un errore di runtime in un errore di compilazione.

Esempio: consente di chiamare l'interfaccia IFoo. Uno dei miei programmi si occupava di un oggetto COM che aveva più percorsi per IFoo (gerarchia ereditaria molto complicata). Sfortunatamente l'implementazione dell'oggetto COM sottostante non ha realizzato che avevano più percorsi per IFoo. Presumevano che fosse sempre il più a sinistra. Quindi all'interno del loro codice, il seguente schema era molto comune

   void SomeMethod(IFoo* pFoo) {
        CFooImpl *p = (CFooImpl)pFoo;
   }

Il secondo IFoo ha comunque causato il " risultante; p " il puntatore è completamente non valido (l'ereditarietà multipla è pericolosa).

La soluzione a lungo termine era che il proprietario dell'oggetto COM risolvesse questo problema. A breve termine, però, dovevo assicurarmi di restituire sempre l'IFoo corretto. Potrei garantire di avere l'IFoo appropriato usando un QI ed evitando qualsiasi cast implicito con IFoo. Così ho creato un nuovo CComPtr & Lt; & Gt; implementazione e ha aggiunto la seguente sostituzione al metodo uguale.

template <typename T>
CComPtr<T>& operator=(const T* pT)  { 
// CComPTr Assign logic
}
template <>
CComPtr<IFoo> operator=<IFoo>(const IFoo* pT) {
  COMPILE_ERROR();
}

Questo ha rivelato rapidamente ogni singolo posto che ho implicitamente assegnato a IFoo.

Non di uso pratico (tranne forse per i test del compilatore), ma metatrace è un Whitted-Style (ovvero ricorsivo e deterministico) ray tracer che genera immagini come quelle al momento della compilazione:

esempio di metatrace

Alcune parti più complesse del codice possono essere visualizzate in fixp.hh , che ha un'implementazione di sqrt a virgola fissa usando l'Airone metodo o sphere.hh che mostra raggio / sfera-intersezione calcolo.

Blitz ++ fa alcune cose impressionanti con i template (ad esempio, una singola riga di codice leggibile può essere trasformato in un set di loop su un array multidimensionale, ottimizzato automaticamente per il miglior ordine di attraversamento).

Esempio di metaprogrammazione più interessante: indurre il compilatore a calcolare un elenco di numeri primi. Non molto pratico, ma impressionante.

Un uso pratico sono le dichiarazioni di asserzione in fase di compilazione, ovvero causando un errore di compilazione se una condizione booleana non è valida.

Dovrei dire Boost.Lambda, Boost.Function e Boost.Bind e il modo in cui lavorano tutti insieme senza problemi. Offrono un'interfaccia davvero intuitiva e rendono la programmazione funzionale il più semplice possibile in un linguaggio che non è stato creato appositamente per questo.

luabind è un bell'esempio pratico, piuttosto un bel dsl vincolante per legare le classi C ++ a lua

BOOST_FOREACH

Asserzione statica (aumenta la versione qui )

(Nota: il supporto integrato per range-based per loop e asserzioni statiche è introdotto in C ++ 11)

Ho posto una domanda non molto tempo fa: Conoscenza delle classi del runtime C++ e la risposta che ho ricevuto da un utente StackOverflow "Denice" era un URL di un sito web Spazio carne:Registrazione della classe runtime C++.

Penso che sia un modo davvero interessante per utilizzare modelli e istanziare oggetti che derivano tutti da una classe base, in modo che quando ho 10 file C++, possano semplicemente aggiungere AUTO_REGISTER_BASE() in fondo e quando tutto è tutto fatto e collegato, solo le classi/file che lo hanno creato verranno registrate, quindi in fase di esecuzione è possibile passare tra le diverse classi disponibili e quelle che non sono disponibili non sono registrate e quindi non possono essere chiamate accidentalmente.

Esistono molti modi diversi dipendenti dal sistema operativo per eseguire la notifica degli eventi (select(), kqueue(), /dev/epoll, Solaris ha la sua cosa, poll()), e avevo bisogno di un modo per far esistere tutti i file di classe in la directory, ma a seconda del sistema operativo in cui veniva eseguito il Makefile, ne avrebbe compilati solo alcuni.Avevo bisogno di un modo per sapere in fase di esecuzione quali erano disponibili e di avere un modo per il programmatore che utilizza la libreria di selezionare le proprie preferenze, tuttavia se non fosse disponibile utilizzare semplicemente quella che aveva più senso logico per la piattaforma (ognuno di loro hanno dei pesi assegnati).

Il codice sopra mi ha aiutato a raggiungere questo obiettivo, con alcune modifiche sostanziali, ma mi ha comunque aiutato!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top