C ++ - Warum wird hier das Schlüsselwort 'template' benötigt?

9

Ich habe folgenden Code:

template <typename TC>
class C
{
    struct S
    {
        template <typename TS>
        void fun() const
        {}
    };

    void f(const S& s)
    {
        s.fun<int>();
    }
};

// Dummy main function
int main()
{
    return 0;
}

Beim Erstellen mit gcc 9.2 und clang (9.0) wird ein Kompilierungsfehler angezeigt, da das templateSchlüsselwort zum Aufrufen erforderlich ist fun. Clang zeigt:

error: use 'template' keyword to treat 'fun' as a dependent template name
        s.fun<int>();
          ^
          template 

Ich verstehe nicht, warum der Compiler funim Kontext von denkt, dass es sich um einen abhängigen Namen handelt f, da fes sich nicht um eine Vorlage selbst handelt. Wenn ich Czu einer regulären Klasse anstelle einer Vorlage wechsle , verschwindet der Fehler. Ich verstehe jedoch nicht, warum es überhaupt einen Fehler geben sollte, da weder Snoch fabhängig davon TC.

Seltsamerweise kompiliert MSVC 19.22 dies ganz gut.


Hinweis

Bevor ich abstimme, um als Betrüger von Wo und Warum zu schließen, muss ich die Schlüsselwörter "Vorlage" und "Typname" eingeben? Bitte beachten Sie, dass dies ein Sonderfall ist, in dem selbst wenn Ses sich tatsächlich um einen abhängigen Namen handelt, dieser im Kontext fnicht abhängig wäre, wenn sie nicht Mitglieder der aktuellen Instanziierung wären.

Martin
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Bhargav Rao

Antworten:

10

Bedenken Sie :

template<typename T>
struct C
{
    struct S
    {
        int a = 99;
    };

    void f(S s, int i)
    {
        s.a<0>(i);
    }
};

template<>
struct C<long>::S
{
    template<int>
    void a(int)
    {}
};

int main()
{
    C<int>{}.f({}, 0); // #1
    C<long>{}.f({}, 0); // #2
}

s.a<0>(i)enthält zwei Vergleichsoperationen wird als Ausdruck analysiert <und >, und dies ist gut für # 1 , aber nicht für die # 2.

Wenn dies geändert wird , s.template a<0>(i)ist # 2 OK und # 1 schlägt fehl. Daher ist das templateSchlüsselwort hier niemals redundant.

MSVC kann den Ausdruck s.a<0>(i)innerhalb desselben Programms in beide Richtungen interpretieren . Dies ist jedoch nach dem Standard nicht korrekt; Jeder Ausdruck sollte nur eine Analyse enthalten, mit der der Compiler umgehen kann.

ecatmur
quelle
Ich verstehe das immer noch nicht ganz. Ihr Beispiel zeigt, dass Sie in diesem Fall entweder die eine Coder die andere Spezialisierung verwenden , aber niemals beide instanziieren können. Das templateSchlüsselwort hier ist meiner Meinung nach immer noch nicht erforderlich, da es davon Sabhängt, welches CSie instanziieren, welches ausgewählt wird. Ohne das templateSchlüsselwort könnten Sie beide instanziieren, und das Verhalten von f würde für jede Instanz unterschiedlich sein.
Martin
2
@Martin der Punkt ist, dass jedes Token nur eine syntaktische Rolle in der Quelldatei haben sollte. Beispielsweise ist es nicht in Ordnung, dass das Token <in einer Vorlageninstanziierung ein Vergleichsoperator und in einer anderen Instanziierung eine Öffnungswinkelklammer ist. Dies soll sicherstellen, dass Compiler Vorlagen in einem AST analysieren können (mit Platzhaltern für Vorlagentypen).
ecatmur
Das macht Sinn. Vielen Dank!
Martin
7

funkann eine Vorlagenfunktion sein oder nicht (oder überhaupt nicht vorhanden sein), abhängig vom Vorlagenparameter von class C.

Das liegt daran, dass Sie sich spezialisieren können S(ohne sich zu spezialisieren C):

template <> struct C<int>::S {};

Da der Compiler funbeim ersten Betrachten class C(vor dem Ersetzen des Vorlagenparameters) wissen möchte, ob es sich um eine Vorlage handelt oder nicht , templateist dies erforderlich.

HolyBlackCat
quelle
1
Geist ... geblasen ...
Bolov
Die Folge davon ist also, ob auf diese neuen Definitionen von Sjemals zugegriffen werden kann f. Wenn dies nicht möglich ist, macht es keinen Sinn, diese Einschränkung zu haben, da fsie sowieso nicht angezeigt werden können.
Martin
@Martin Mit GCC finden Clang und MSVC fes.
HolyBlackCat
@bolov Ja, du kannst dich auf viele verschiedene Dinge spezialisieren .
HolyBlackCat