Haftungsausschluss
Dies ist keine Antwort, sondern ein langer Kommentar
Meine Kenntnisse als Sprachanwalt sind zu gering, um den Standard vollständig zu verstehen, aber hier sind einige Dinge, die ich beim Experimentieren mit dem Code entdeckt habe. Alles, was folgt, basiert auf meinem (alles andere als perfekten) Verständnis der Angelegenheit und benötigt wahrscheinlich einige Überprüfungen.
Ermittlung
Zunächst ging ich zu einer vollständig definierten Standardversion (C ++ 17), damit wir an einer genau definierten Implementierung arbeiten.
Wenn man sich diesen Code ansieht, scheint es, dass MSVC immer noch einige Probleme hat (mit seiner Suche, denke ich?), Wenn es um die Instanziierung und Neudefinition von Vorlagen geht. Ich würde MSVC in unserem Szenario nicht so sehr vertrauen.
Lassen Sie uns darüber nachdenken, warum wir das templateSchlüsselwort bei brauchen könnten
return yF.template head<1>();
Abhängige Namen
In Vorlagen müssen wir dem Compiler manchmal bei der Entscheidung helfen, ob sich ein Name auf ihn bezieht
- ein Wert
int T::x = 0,
- ein Typ
struct T::x {};oder
- eine Vorlage
template <typename U> T::foo<U>();
Wenn wir uns auf einen Wert beziehen, tun wir nichts. Wenn wir uns auf einen Typ beziehen, müssen wir verwenden typename. Und wenn wir uns auf eine Vorlage beziehen, die wir verwenden template. Mehr zu diesem Thema finden Sie hier .
Ich verstehe die Standardspezifikation nicht, wenn es um die tatsächliche Definition eines abhängigen Namens geht, aber hier sind einige Beobachtungen.
Beobachtungen
Schauen wir uns den Referenzcode an
template <int N>
struct Matrix
{
template <int Idx>
int head() { return Idx; }
};
template <typename T>
struct Test
{
static constexpr int RayDim = 3;
int func() const
{
Matrix<RayDim> yF;
return yF.head<1>(); // clang complains, gcc and msvc are ok
}
};
struct Empty {};
int test()
{
Test<Empty> t;
return t.func();
}
Normalerweise RayDimsollte es sich um einen abhängigen Namen handeln (da er sich in der Vorlage befindet Test), der auch Matrix<RayDim>zu einem abhängigen Namen führen würde. Nehmen wir zunächst an, dass es sich Matrix<RayDim>tatsächlich um einen abhängigen Namen handelt. Dies macht auch Matrix<RayDim>::headeinen abhängigen Namen. Da Matrix<RayDim>::heades sich um eine Vorlagenfunktion handelt, handelt es sich um eine Vorlage an sich, und es gelten die Regeln für abhängige Namen von oben, sodass wir das templateSchlüsselwort verwenden müssen. Darüber beschwert sich Clang.
Da es jedoch innerhalb derselben Vorlage RayDimdefiniert ist Testund funcauch innerhalb derselben Vorlage definiert ist und keine Vorlagenfunktion an sich, denke ich nicht, dass dies RayDimtatsächlich ein abhängiger Name im Kontext von ist func. Darüber hinaus RayDimstützt sich nicht auf die Vorlagenargumente von Test. In diesem Fall Matrix<RayDim>und Matrix<RayDim>::headjeweils würden, werden nicht-abhängige Namen, die uns die weglassen können templateSchlüsselwort. Aus diesem Grund kompilieren gcc (und msvc).
Wenn wir auch eine Vorlage RayDimerstellen würden, wie hier
template <typename>
static constexpr int RayDim = 3;
gcc würde es auch als abhängigen Namen behandeln (was richtig ist, da es später möglicherweise eine Vorlagenspezialisierung gibt, sodass wir es zu diesem Zeitpunkt noch nicht wissen). In der Zwischenzeit akzeptiert msvc gerne alles, was wir darauf werfen.
Fazit
Es scheint, als würde es darauf ankommen, ob RayDimes sich um einen abhängigen Namen im Kontext von handelt Test<T>::funcoder nicht. Clang glaubt es ist, gcc nicht. Von einigen weiteren Tests sieht es aus wie MSVC-Seiten mit Klirren auf diesem. Aber es macht auch irgendwie sein eigenes Ding, also wer weiß?
Ich würde mich hier auf die Seite von gcc stellen, da ich keine Möglichkeit sehe RayDim, an dem Punkt, an dem funcinstanziiert wird , abhängig zu werden .