Ich versuche die folgenden Codefragmente zu verstehen
Snippet # 1
template <typename T>
struct A
{
static constexpr int VB = T::VD;
};
struct B : A<B>
{
};
Weder gcc9 noch clang9 werfen hier einen Fehler.
F. Warum wird dieser Code kompiliert? Instanziieren wir nicht, A<B>
wenn wir von B erben? Es gibt kein VD in B, sollte der Compiler hier also keinen Fehler auslösen?
Snippet # 2
template <typename T>
struct A
{
static constexpr auto AB = T::AD; // <- No member named AD in B
};
struct B : A<B>
{
static constexpr auto AD = 0xD;
};
In diesem Fall wird gcc9 gut kompiliert, aber clang9 gibt den Fehler "Kein Mitglied mit dem Namen AD in B" aus.
F. Warum wird es mit gcc9 kompiliert / warum wird es nicht mit clang9 kompiliert?
Snippet # 3
template <typename T>
struct A
{
using TB = typename T::TD;
};
struct B : A<B>
{
using TD = int;
};
Hier werfen sowohl clang9 als auch gcc9 einen Fehler. gcc9 sagt "ungültige Verwendung des unvollständigen Typs 'Struktur B'".
F. Wenn Struktur B hier unvollständig ist, warum ist sie dann in Snippet 2 nicht unvollständig?
Verwendete Compiler-Flags : -std=c++17 -O3 -Wall -Werror
. Danke im Voraus!!!
quelle
struct B
Instanziiert nichtA
mitB
?B
ist unvollständig ... Aber unsicher, wann Mitglied instanziiert werden soll ..Antworten:
Ich glaube, diese beschränken sich im Wesentlichen auf [temp.inst] / 2 (Hervorhebung von mir):
und [temp.inst] / 9
Der Wortlaut des Standards zur impliziten Instanziierung von Vorlagen lässt viele Details für die Interpretation offen. Im Allgemeinen scheint es mir, dass Sie sich einfach nicht darauf verlassen können, dass Teile einer Vorlage nicht instanziiert werden, es sei denn, die Spezifikation sagt dies ausdrücklich aus. Somit:
Snippet # 1
Sie instanziieren
A<B>
. Durch das Instanziieren werden jedochA<B>
nur die Deklarationen instanziiert, nicht die Definitionen der statischen Datenelemente.VB
wird niemals so verwendet, dass eine Definition erforderlich wäre. Der Compiler sollte diesen Code akzeptieren.Snippet # 2
Wie von Jarod42 hervorgehoben, ist die Erklärung von
AB
enthält einen Platzhaltertyp. Es scheint mir, dass der Wortlaut des Standards nicht wirklich klar ist, was hier passieren soll. Löst die Instanziierung der Deklaration eines statischen Datenelements, das einen Platzhaltertyp enthält, einen Platzhaltertypabzug aus und stellt somit eine Verwendung dar, die die Definition des statischen Datenelements erfordert? Ich kann in der Norm keinen Wortlaut finden, der eindeutig Ja oder Nein dazu sagt. Daher würde ich sagen, dass beide Interpretationen hier gleichermaßen gültig sind und somit sowohl GCC als auch Clang richtig sind…Snippet # 3
Ein Klassentyp ist erst an dem Punkt vollständig, an dem Sie das Schließen
}
des Klassenspezifizierers [class.mem] / 6 erreichen . SomitB
ist während der impliziten InstanziierungA<B>
in all Ihren Snippets unvollständig . Es ist nur so, dass dies für Snippet # 1 irrelevant war. In Snippet # 2 hat clangNo member named AD in B
als Ergebnis einen Fehler ausgegeben . Ähnlich wie im Fall von Snippet Nr. 2 kann ich keine Formulierung finden, wann genau die Alias-Deklarationen der Mitglieder instanziiert würden. Anders als bei der Definition statischer Datenelemente gibt es jedoch keinen Wortlaut, der die Instanziierung von Elementaliasdeklarationen während der impliziten Instanziierung einer Klassenvorlage explizit verhindert. Daher würde ich sagen, dass das Verhalten von GCC und Clang in diesem Fall eine gültige Interpretation des Standards ist…quelle
constexpr
statische Datenelement nur eine Deklaration. C ++ 17 hatinline
Variablen gewonnen undconstexpr
impliziertinline
, und dies macht die Deklaration statischer Datenelemente im Hauptteil zu einer Definition.auto
Fall besagt die Regel jedoch, dass die Deklaration eine Initialisierungsdeklaration sein muss. Dies kann nur der Fall sein, wenn bekannt ist, dass es sich bei der Erklärung um eine Definition handelt (soweit ich weiß. Ich war eine Weile außerhalb des Anwaltslandes). In der Vergangenheit gab es einen ähnlichen Fall und eel.is/c++draft/temp.inst#2.sentence-3 wurde hinzugefügt, wobei eine Deklaration, die eine Definition ist, als "bekannt als Definition" instanziiert wird, ohne tatsächlich Instanziieren der Definition.