Enthüllung der Nuancen der Metaprogrammierung zur Kompilierungszeit
Im Bereich der Selbstbeobachtung besteht die Notwendigkeit dazu Weisen Sie zur Kompilierungszeit dynamisch eindeutige Bezeichner zu oder führen Sie ähnliche Vorgänge für Typen aus. Obwohl es sich bei der Template-Metaprogrammierung im Wesentlichen um eine funktionale Sprache handelt, fehlen ihr offenbar die notwendigen globalen Variablen und der veränderbare Zustand, um diese Operationen zu implementieren.
Überraschenderweise liegt die Antwort auf dieses Dilemma in der Schnittstelle zwischen Funktionssuche und Namespace-Scope-Funktionalität . Die Funktionssuche bietet eine Möglichkeit, den numerischen Zustand aus einem definierten Satz deklarierter Funktionen zu extrahieren.
Im folgenden Beispiel zeigen wir, wie diese Technik angewendet werden kann, um eine Zählung zur Kompilierungszeit zu erreichen:
template< size_t n > // This type returns a number through function lookup. struct cn // The function returns cn<n>. { char data[ n + 1 ]; }; // The caller uses (sizeof fn() - 1). template< typename id, size_t n, size_t acc > cn< acc > seen( id, cn< n >, cn< acc > ); // Default fallback case. /* Evaluate the counter by finding the last defined overload. Each function, when defined, alters the lookup sequence for lower-order functions. */ #define counter_read( id ) \ ( sizeof seen( id(), cn< 1 >(), cn< \ ( sizeof seen( id(), cn< 2 >(), cn< \ ( sizeof seen( id(), cn< 4 >(), cn< \ ( sizeof seen( id(), cn< 8 >(), cn< \ ( sizeof seen( id(), cn< 16 >(), cn< \ ( sizeof seen( id(), cn< 32 >(), cn< 0 \ /* Add more as desired; trimmed for Stack Overflow code block. */ \ >() ).data - 1 ) \ >() ).data - 1 ) \ >() ).data - 1 ) \ >() ).data - 1 ) \ >() ).data - 1 ) \ >() ).data - 1 )
#define counter_inc( id ) \ cn< counter_read( id ) + 1 > \ seen( id, cn< ( counter_read( id ) + 1 ) & ~ counter_read( id ) >, \ cn< ( counter_read( id ) + 1 ) & counter_read( id ) > )
Dieser Ansatz ermöglicht die Zuweisung eindeutiger Bezeichner und die Erstellung von Datenstrukturen mit durch die Kompilierzeit bestimmten Größen. Es ist erwähnenswert, dass diese Technik auch mit dem Schlüsselwort constexpr von C 11 implementiert werden kann, wie im aktualisierten Code unten gezeigt:
#define COUNTER_READ_CRUMB( TAG, RANK, ACC ) counter_crumb( TAG(), constant_index< RANK >(), constant_index< ACC >() ) #define COUNTER_READ( TAG ) COUNTER_READ_CRUMB( TAG, 1, COUNTER_READ_CRUMB( TAG, 2, COUNTER_READ_CRUMB( TAG, 4, COUNTER_READ_CRUMB( TAG, 8, \ COUNTER_READ_CRUMB( TAG, 16, COUNTER_READ_CRUMB( TAG, 32, COUNTER_READ_CRUMB( TAG, 64, COUNTER_READ_CRUMB( TAG, 128, 0 ) ) ) ) ) ) ) ) #define COUNTER_INC( TAG ) \ constexpr \ constant_index< COUNTER_READ( TAG ) + 1 > \ counter_crumb( TAG, constant_index< ( COUNTER_READ( TAG ) + 1 ) & ~ COUNTER_READ( TAG ) >, \ constant_index< ( COUNTER_READ( TAG ) + 1 ) & COUNTER_READ( TAG ) > ) { return {}; }
Zusammenfassend lässt sich sagen, dass bei der herkömmlichen Vorlagen-Metaprogrammierung zwar keine Nebenwirkungen auftreten, es jedoch möglich ist, einen Namespace zu erreichen -Bereichszählerfunktionalität durch Nutzung der Funktionssuche und der oben genannten Techniken. Diese Methoden bieten eine praktische Lösung für die dynamische Zuweisung eindeutiger Bezeichner und die Bestimmung der Größe von Datenstrukturen zur Kompilierungszeit, wodurch die Introspektionsfähigkeiten von C-Anwendungen verbessert werden.
Das obige ist der detaillierte Inhalt vonWie können Kompilierzeitzähler mithilfe der Funktionssuche und der Namespace-Scope-Funktionalität in C implementiert werden?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!