Ich habe festgestellt, dass beim Zugriff auf ein Nichtvorlagenattribut (v.foo
) aus einer Variablen eines Vorlagentyps (T& v
) C++ dazu verleitet werden kann zu denken, dass es eine Membervorlage ist ist eine gleichnamige Template-Funktion (template class <T> void foo()
). Wie kann dies anhand der C++ - Spezifikation erklärt werden? Betrachten Sie dieses einfache Programm:C++ verwirrender Attributname für Elementvorlage
#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-Funktion foo_negative
, die ein Objekt eines beliebigen Typs nimmt und bestimmt, ob seine foo Attribut negativ ist. Die main
Funktion instanziiert foo_negative
mit [T = X]. Dieses Programm kompiliert und läuft ohne Ausgabe. Jetzt
, fügen Sie diese Funktion an die Spitze des Programms:
template <class T>
void foo()
{
}
es mit G ++ 4.6.3 Ergebnisse in dieser Compiler-Fehler Kompilieren:
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 ist return v.foo < 0
und Zeile 25 ist assert(!foo_negative(x))
.)
Clang erzeugt ähnliche Fehler.
Wat? Wie konnte das Hinzufügen einer nicht verwandten Funktion, die nie aufgerufen wird, einen Syntaxfehler in ein gültiges Programm einführen? Beim Parsen foo_negative
kennt der Compiler den Typ v
nicht. Entscheidend ist, ob v.foo
eine Membervorlage oder ein reguläres Member ist. Offensichtlich muss es sich bei der Parsing-Zeit entscheiden (bevor die Vorlage instanziiert wird), ob sie als Elementvorlage oder als normales Element behandelt werden soll.
Wenn er denkt, v.foo
Mitglied Vorlage ist, dann wird < 0
als vorbei 0
als Template-Argument gesehen, und es gibt eine fehlende >
, daher der Syntaxfehler. Wenn dann foo_negative
mit [T = X] instanziiert wird, gibt es einen weiteren Fehler, da X::foo
keine Member-Vorlage ist.
Aber warum denkt es v.foo
ist ein Mitglied Vorlage? Diese Ambiguität ist genau das, was das Schlüsselwort template
ist: Wenn ich v.template foo
schreiben würde, dann würde ich C++ explizit auffordern, eine Mitgliedervorlage zu erwarten, aber ich habe das Schlüsselwort template
nicht verwendet! Ich habe mich nicht auf eine Mitgliedervorlage bezogen, daher sollte angenommen werden, dass es sich um ein reguläres Mitglied handelt. Die Tatsache, dass es eine Funktion mit dem gleichen Namen wie das Mitglied gibt, sollte keine Wirkung haben. Warum geht das? Es kann kein Fehler im Compiler sein, weil GCC und Clang konsistent sind.
Das ist seltsam. Es kompiliert auf gcc-4.3.4: http://ideone.com/FP3SO –
Nein, Sie haben vergessen, die 'Vorlage void foo()' Erklärung hinzuzufügen: http://ideone.com/FxEBm Es kompiliert nicht . –
mgiuca
vielleicht ist es wirklich ein Fehler sowohl in gcc und clang: [Deklaration] (http://ideone.com/zofCF). Ich änderte 'v.foo < 0' to '0 > v.foo' und es kompiliert fein. Vielleicht denken beide Compiler, dass "<0" ein Vorlagenargument ist, wie Sie in der Frage erwähnt haben. – user2k5