template/ typetrait Problem
-
Weiss jemand, ob folgender Code C++ konform ist? Er scheint naemlich nicht mit jedem Compiler zu funktionieren. Zum Beispiel versteht clang das Test<T>::is_int b; nicht und meldet, das nach Test ein ";" erwartet wird. Ein Test<int>::is_int b; hingegen versteht er.
#include <type_traits> template<typename t> struct Test { typedef std::false_type is_int; }; template<> struct Test<int> { typedef std::true_type is_int; }; template<typename T> void testfunc() { Test<T>::is_int b; }
-
typename Test<T>::is_int b;
-
Danke!
-
Grundlagen nach 12 Jahren noch nicht gelernt

*scherz*
-
Hatte irgendwie in Erinnerung, das typename vor das T kommt. Dem MS Compiler isses egal.
-
warum wird das dann nicht aus dem standart entfernt, wenn es compiler selbst erkennen können?

-
der Compiler untersucht i.a. das Template schon an der Stelle, wo es definiert wird, unabh. davon, ob es später verwendet wird. und dabei möchte er gern wissen, was ein Typname ist und was nicht und bittet den Programmierer um freundliche Unterstützung
-
anti-typename schrieb:
warum wird das dann nicht aus dem stan**** entfernt, wenn es compiler selbst erkennen können?

Weil sie es nicht können. Sie können bloß raten, dass dies ein typischer Fehler ist und die andere Möglichkeit, dass dort irgendein Operator fehlt, eher selten falsch gemacht wird. Aber woher sollten sie wissen, dass dies nicht doch so gewollt war? Dann läge nämlich eine völlig andere Art von Fehler vor. Das typename-Schlüsselwort hebt diese Doppeldeutigkeit auf und macht es möglich, die Falschheit oder Richtigkeit des Codes genau zu erkennen.
Akademisches Vorzeigebeispiel:
extern int j; template <class T> void foo() { T::i * j; }Multiplikation oder Zeigerdefinition? Diese Frage ist wichtig, weil davon abhängt, ob das Template korrekt instanziert werden kann oder nicht. Es darf hier nicht von T abhängen, was passiert.
Jetzt "vergessen" wir den Stern:
template <class T> void foo() { T::i j; }Und schon haben wir TGGCs Code. Variablendefinition oder Sternchen vergessen? Klar, der erste Fall ist wahrscheinlicher, aber wirklich wissen kann man es nur, indem der Programmierer seine Absicht bekannt macht.
-
Also wenn "T::i j;" eine gueltige Variablendefinition waere, dann kann es natuerlich keine Multiplikation sein. Das Problem ensteht doch erst, wenn "T::i j;" das eine bedeutet und "typename T::i j;" aber was anderes. Mich hatte nur verwundert, das es mit dem <int> funktioniert, aber nicht mit dem <T>. Wenn ich dich richtig verstehe, liegt das daran, das bei <int> der Compiler dann direkt nachschauen kann, aber bei <T> die konkrete Bedeutung erst spaeter festgelegt wird.
-
TGGC schrieb:
das bei <int> der Compiler dann direkt nachschauen kann, aber bei <T> die konkrete Bedeutung erst spaeter festgelegt wird.
Ja. Aber wichtig: Die Bedeutung muss ja im Voraus fest stehen, weil der Programmierer die Bedeutung festlegt. Um mein Beispiel mit der Multiplikation mal ausführlicher zu machen:
extern int j; template <class T> void foo() { T::i * j; } struct A { typedef int i; }; struct B { static int i; }; [...] foo<A> (); foo<B> ();Soll da jetzt in einem Fall ein Pointer definiert werden und im anderen Fall eine Multiplikation durchgeführt werden? Das ist garantiert nicht, was der Programmierer von foo beabsichtigt hat. Er hat nur eines von beidem gemeint, daher muss er seine Absicht klar machen. Denn entweder foo<A> oder foo<B> ist hier keine gültige Instanzierung des Templates foo, der Compiler muss herausfinden können, welche davon falsch ist.
-
siehe auch
14.6 Name resolution
2 A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.
-
Test<T>::is_int ist ein dependent name, d. h. seine Bedeutung ist abhängig von den Parametern der umgebenden Template. Für dependent names gelten eine Reihe besonderer Regeln, darunter die, dass Typnamen und Templates explizit gekennzeichnet werden müssen, damit der Parser sie von Objektnamen unterscheiden kann.
Beispiel:
typename foo<T>::template bar<int>::type varname;Auf diese Weise kann der Compiler beim Parsen der Template schon Aussagen über sie treffen und nicht erst, wenn daraus eine konkrete Klasse/Funktion gestanzt wird.
Zudem lassen sich eine Reihe mehrdeutiger Ausdrücke formulieren, wenn man diese Regel nicht hat, etwa
a < b > ::c < d > e; // bzw. associative_containers<T>::map<U> m;Das sieht jezt etwas konstruiert aus, aber wenn man mal TMP mit einem uralten Compiler versucht hast, scheinen solche Probleme nicht mehr so weit hergeholt.