Ist es möglich zu überprüfen, ob ein Template-Typ zur Kompilierzeit instanziiert wurde, damit ich diese Informationen in einer enable_if-Spezialisierung verwenden kann?
Sagen wir, ich habe
%Vor%Kann ich irgendwie einen is_known_type definieren, dessen Wert wahr ist, wenn der bekannte Typ zur Kompilierzeit instanziiert wird?
Dies ist möglich, wenn Sie die Tatsache nutzen, dass bestimmte Ausdrücke an Stellen verwendet werden, an denen constexpr
s erwartet werden, oder nicht, und dass Sie abfragen können, um zu sehen, welcher Status für jeden Ihrer Kandidaten gilt. Speziell in unserem Fall ist die Tatsache, dass constexpr
s ohne Definition nicht als konstante Ausdrücke übergeben werden kann und noexcept
ist eine Garantie für konstante Ausdrücke. Daher zeigt noexcept(...)
, das true
zurückgibt, das Vorhandensein einer richtig definierten constexpr
an.
Im Wesentlichen behandelt dies constexpr
s als Ja / Nein-Schalter und führt den Status zur Kompilierzeit ein.
Beachten Sie, dass dies ein Hack ist, Sie benötigen Umgehungslösungen für bestimmte Compiler (siehe die folgenden Artikel), und diese spezifische friend
-basierte Implementierung könnte von künftigen Versionen des Standards als fehlerhaft angesehen werden.
Mit dem aus dem Weg ...
Filip Roséen präsentiert dieses Konzept in Der Artikel ist speziell diesem Thema gewidmet.
Seine Beispielimplementierung ist mit zitierten Erklärungen:
%Vor%%Vor%Eine constexpr-Funktion kann in einem von zwei Zuständen sein; Entweder ist es verwendbar in einem konstanten Ausdruck, oder es ist nicht - wenn es a fehlt Definition es fällt automatisch in die letztere Kategorie - es gibt keine anderer Zustand (außer wir betrachten nicht definiertes Verhalten).
Normalerweise sollten constexpr-Funktionen genau so behandelt werden, wie sie sind sind; Funktionen, aber wir können sie auch als individuelle Handles sehen "Variablen" haben einen ähnlichen Typ wie bool, wo jede "Variable" stehen kann habe einen von zwei Werten; verwendbar oder nicht verwendbar.
In unserem Programm hilft es, wenn Sie die Flagge als genau betrachten; ein Griff (keine Funktion). Der Grund ist, dass wir nie Flagge nennen werden In einem evaluierten Kontext interessiert uns nur sein aktueller Zustand.
%Vor%writer ist eine Klassenvorlage, die nach der Instantiierung ein Definition für eine Funktion in ihrem umgebenden Namensraum (mit dem Signatur-Int-Flag (Tag), wobei Tag ein Template-Parameter ist.
Wenn wir noch einmal an constexpr denken, dass es für einige als Handles fungiert Variabel können wir eine Instantiierung des Schreibers als unbedingtes Schreiben des Wertes, der für die Variable hinter dem Funktion in der Friend-Deklaration.
%Vor%Ich wäre nicht überrascht, wenn Sie denken, dass dependent_writer aussieht wie ein ziemlich sinnlose Indirektion; warum nicht direkt Schriftsteller instanziieren wo wir es verwenden wollen, anstatt durch dependent_writer zu gehen?
- Instantiierung des Schreibers muss von etwas abhängen, um sofortige Instanziierung zu verhindern, und;
- dependent_writer wird in einem Kontext verwendet, in dem ein Wert vom Typ bool als Abhängigkeit verwendet werden kann.
Das oben könnte ein bisschen komisch aussehen, aber es ist wirklich ziemlich einfach;
- setzt B = true, wenn flag (0) ein konstanter Ausdruck ist, andernfalls B = false und;
- instanziiert instantly_writer (sizeof benötigt einen vollständig definierten Typ).
Das Verhalten kann mit dem folgenden Pseudocode ausgedrückt werden:
%Vor%
Endlich, der Proof of Concept:
%Vor% Ich habe das auf Ihr spezielles Problem angewendet. Die Idee ist, mit den Schaltern constexpr
Yes / No anzugeben, ob ein Typ instanziiert wurde. Sie benötigen also einen separaten Schalter für jeden Typ, den Sie haben.
inst_check_wrapper<T>
umschließt im Wesentlichen einen Schalter für den Typ, den Sie ihm geben. Es ist nur eine generische Version des ursprünglichen Beispiels.
Der Switch-Toggler ist identisch mit dem im ursprünglichen Beispiel. Es kommt mit der Definition für den Schalter eines Typs, den Sie verwenden. Um eine einfache Überprüfung zu ermöglichen, fügen Sie einen Helper Switch Inspector hinzu:
%Vor%Schließlich registriert sich der Typ selbst als initialisiert. In meinem Fall:
%Vor%Der Schalter wird eingeschaltet, sobald dieser spezielle Konstruktor angefordert wird. Beispiel:
%Vor%Nein, eine Kompilierzeitprüfung für nicht instanziierte Klassen ist nicht möglich. Sie können jedoch eine (statische) Zuordnung von instanziierten Klassen (im Debug-Build) erstellen, die Sie zur Laufzeit überprüfen können.
Es sollte jedoch möglich sein, die verknüpfte Binärdatei zu analysieren, indem eine Liste erwarteter instanziierter Klassen mit tatsächlich instanziierten Klassen verglichen wird (aber das ist nach der Kompilierzeit und nach meinem Wissen).
Es gibt keine Möglichkeit, das zu tun. Also würde ich sagen: Nein.
Tags und Links c++ c++11 templates typetraits