Ich versuche eine andere Template-Spezialisierung für Klassen zu haben, die eine innere Klasse mit einem bestimmten Namen haben. Ich habe einen Hinweis von hier genommen und Folgendes versucht :
%Vor% Wie Sie sehen können, funktioniert es, wenn ich in typedef
nach einem FooWithTypedef
-definierten Typ suche. Es funktioniert jedoch nicht, wenn der Typ eine echte innere Klasse ist. Es funktioniert auch nur, wenn der typedef
-ed-Typ in FooWithTypedef
mit dem Standardwert des zweiten Arguments in der ursprünglichen Templatendeklaration übereinstimmt (in meinem Beispiel void
). Kann man erklären, was hier vor sich geht? Wie funktioniert der Spezialisierungsprozess hier?
Beantworten Sie die erste Frage
Die Template-Spezialisierung, die Sie hier definiert haben:
%Vor% wird wirksam, wenn jemand den Datentyp HasXYZ<A,A::XYZ>
für einen bestimmten Datentyp A
verwendet.
Beachten Sie, dass A
, unabhängig von A::XYZ
, ein Datentyp ist, der völlig unabhängig von A
ist. Innere Klassen sind eigenständige Datentypen. Wenn Sie A
als erstes Template-Argument verwenden, gibt es absolut keinen Grund dafür, dass der Compiler annimmt, dass Sie etwas mit dem Namen A:XYZ
als zweites Argument verwenden möchten, auch wenn eine innere Klasse dieses Namens existiert, und selbst wenn Dies würde den Compiler zu einer Template-Spezialisierung führen, die exakt mit den Template-Argumenten übereinstimmt. Vorlagenspezialisierungen werden basierend auf den vom Coder bereitgestellten Vorlagenargumenten gefunden und nicht auf weiteren möglichen Vorlagenargumenten basiert.
Wenn Sie also HasXYZ<Foo>
verwenden, wird das Standard-Template-Argument void
für den zweiten Parameter verwendet.
Unnötig zu erwähnen, dass Sie die erwartete Ausgabe erhalten würden, wenn Sie HasXYZ<Foo,Foo:XYZ>
explizit verwenden würden. Aber das ist offensichtlich nicht das, was du beabsichtigt hast.
Ich fürchte, der einzige Weg, um das zu bekommen, was Sie brauchen, ist std::enable_if
(oder etwas, das auf ähnliche Weise funktioniert).
Beantworten Sie die zusätzliche Frage (nach dem Update)
Betrachten Sie die folgende Vereinfachung:
%Vor% Die primäre Definition gibt ein Standardargument von void
für den zweiten Vorlagenparameter an. Aber die Spezialisierung (zweite Definition oben) definiert, wie class A
tatsächlich aussieht, wenn der zweite Vorlagenparameter wirklich ist void
.
Was das bedeutet ist, dass, wenn Sie sagen, A<int>
in Ihrem Code, das Standardargument ergänzt wird, so erhalten Sie A<int,void>
, und dann findet der Compiler die passendste Template-Spezialisierung, die die zweite ist oben.
Während also Standardschablonenargumente als Teil der primären Schablonenklaration definiert sind, bedeutet die Verwendung dieser Schablonen nicht, dass die primäre Schablonendefinition verwendet wird. Dies liegt im Grunde daran, dass Standardschablonenargumente Teil der Schablonendeklaration sind und nicht die Schablonendefinition (*).
Wenn in Ihrem Beispiel typedef void XYZ
in FooWithTypedef
enthalten ist, wird der zweite Vorlagenparameter standardmäßig auf void
gesetzt, und dann wird die passendste Spezialisierung gefunden. Dies funktioniert auch dann, wenn in der Template-Spezialisierung das zweite Argument als T::XYZ
anstelle von void
definiert ist. Wenn diese zum Zeitpunkt der Auswertung gleich sind, wird die Template-Spezialisierung ausgewählt (§14.4 "Typ-Äquivalenz").
(*) Ich habe im Standard keine Aussage gefunden, die das so deutlich sagt. Aber es gibt §14.1 / 10, der den Fall beschreibt, in dem Sie mehrere Deklarationen (aber nur eine primäre Definition) einer Vorlage haben:
(§14.1 / 10) Die Menge der Standardschablonenargumente, die zur Verwendung mit einer Schablonendeklaration oder -definition zur Verfügung stehen, wird durch Zusammenführen der Standardargumente aus der Definition (falls im Geltungsbereich) und allen Deklarationen im Geltungsbereich auf die gleiche Weise erhalten Funktionsargumente sind (8.3.6). [Beispiel:
%Vor%entspricht
%Vor%].
Dies deutet darauf hin, dass der Mechanismus hinter Standardvorlagenargumenten unabhängig von dem ist, der zur Identifizierung der am besten passenden Spezialisierung der Vorlage verwendet wird.
Außerdem gibt es zwei existierende SO-Posts, die sich ebenfalls auf diesen Mechanismus beziehen:
Diese Antwort zu Template-Spezialisierung zur Verwendung des Standardtyps, wenn Klassenmitglied typedef nicht existiert
Standardwerte von Vorlagenparametern in der Klassenvorlage Spezialisierungen
A::XYZ
müsste void
haben, damit die Teilspezialisierung ausgewählt wird, was für einen Klassentyp niemals der Fall sein kann. Eine Möglichkeit, dies zum Laufen zu bringen, ist die Verwendung eines gefälschten abhängigen void
type-Namens:
Eine Erläuterung dazu finden Sie in dieser Frage .
Tags und Links c++ template-specialization sfinae