Wie kann man die Anwesenheit einer inneren Klasse in einer Klasse über SFINAE testen?

8

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?

    
dragonroot 22.08.2012, 06:15
quelle

3 Antworten

4

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

    
jogojapan 22.08.2012, 07:38
quelle
2

Hier ist eine weitere Version, die das Vorhandensein der inneren Klasse erkennt:

%Vor%     
BЈовић 22.08.2012 06:47
quelle
1

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:

%Vor%

Eine Erläuterung dazu finden Sie in dieser Frage .

    
Xeo 22.08.2012 22:35
quelle