Verwirrender C ++ - Attributname für Elementvorlage

Ich habe festgestellt, dass beim Zugriff auf ein Nicht-Template-Attribut (v.foo) aus einer Variablen eines Vorlagentyps (T& v), Kann C ++ zu der Annahme verleitet werden, dass es sich um eine Member-Vorlage handelt, wenn es eine gleichnamige Vorlagenfunktion gibt (template class <T> void foo()). Wie kann dies aus der C ++ - Spezifikation erklärt werden? Betrachten Sie dieses einfache Programm:

#include <cassert>

/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
    return v.foo < 0;
}

struct X
{
    int foo;
};

int main()
{
    X x;
    x.foo = 5;
    assert(!foo_negative(x));
    return 0;
}

Wir haben eine Template-Funktionfoo_negative das nimmt ein Objekt von beliebigem Typ und bestimmt, ob sein Foo-Attribut negativ ist. Dasmain Funktion instanziiertfoo_negative mit [T = X]. Dieses Programm kompiliert und läuft ohne Ausgabe.

Fügen Sie nun diese Funktion oben im Programm hinzu:

template <class T>
void foo()
{
}

Das Kompilieren mit G ++ 4.6.3 führt zu folgendem Compilerfehler:

funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5:   instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function

(Wo Linie 13 istreturn v.foo < 0 und Linie 25 istassert(!foo_negative(x)).)

Clang erzeugt ähnliche Fehler.

Wat? Wie konnte das Hinzufügen einer unabhängigen Funktion, die niemals aufgerufen wird, einen Syntaxfehler in ein gültiges Programm einführen? Beim Parsenfoo_negativekennt der Compiler den Typ nichtvund entscheidend ist, dass es nicht weiß, obv.foo ist eine Mitgliedervorlage oder ein reguläres Mitglied. Anscheinend muss es beim Parsen (bevor die Vorlage instanziiert wird) entscheiden, ob es als Mitgliedervorlage oder als reguläres Mitglied behandelt wird.

Wenn es denktv.foo ist dann eine Mitgliedervorlage< 0 wird als vorübergehend angesehen0 als Template-Argument, und es fehlt ein>Daher der Syntaxfehler. Dann wennfoo_negative wird mit [T = X] instanziiert, liegt ein weiterer Fehler vorX::foo ist keine Mitgliedervorlage.

Aber warum denkt esv.foo ist eine Mitgliedsvorlage? Diese Mehrdeutigkeit ist genau das, was dietemplate Stichwort ist für: wenn ich schriebv.template foo, dann würde ich C ++ explizit sagen, dass es eine Member-Vorlage erwarten soll, aber ich habe die nicht verwendettemplate Stichwort! Ich habe mich nicht auf eine Mitgliedervorlage bezogen, daher sollte davon ausgegangen werden, dass es sich um ein reguläres Mitglied handelt. Die Tatsache, dass es eine gibtFunktion mit dem gleichen Namen wie das Mitglied sollte keine Wirkung haben. Warum ist es so? Es kann kein Fehler im Compiler sein, da GCC und Clang konsistent sind.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage