Darf man Pointer-to-Members als Template-Argumente benutzen?
-
template <typename Base, int Base::* basevar> class c1 { private: Base* base; public: c1 (Base* baddr) : base (baddr) { } int getBaseVar (void) { return (base->*basevar); } }; class c1test { private: int var; public: c1test (void) : c1instance (this), var (0) { } c1 <c1test, &c1test::var> c1instance; // MSVC (7.1) meldet hier, var sei nicht bekannt. Mit BCC und g++ funktioniert es allerdings fehlerfrei. };
Seltsamerweise schluckt MSVC allerdings pointers-to-member-functions als Template-Argumente klaglos.
Sind denn pointers-to-members als Template-Argumente überhaupt standardkonform?Moritz
-
warum nimmst du nicht einen normalen zeiger?
-
Shade Of Mine schrieb:
warum nimmst du nicht einen normalen zeiger?
Wie so oft ist das nur eine entschärfte Variante des Problems, und mir geht es um das Prinzip. Die Originalklasse hat noch einen pointer-to-member-function als Template-Argument, und den enthaltenen Base*-Zeiger brauche ich für den Zugriff darauf. Wenn ich nun noch einen Zeiger in der Klasse speichern muß, braucht diese doppelt so viel Speicher, was ich gerne vermeiden würde.
Moritz
-
Habe ich zwar noch nie gebraucht, aber ich nehme an dass es korrekt ist. comeau bestätigt mich in meiner meinung
-
Shade Of Mine schrieb:
Habe ich zwar noch nie gebraucht, aber ich nehme an dass es korrekt ist. comeau bestätigt mich in meiner meinung
Hmm, ich dachte immer, MSVC sei nahezu perfekt in der Unterstützung des Standards?
Bisher hat sich diese Erfahrung immer bestätigt, zudem war der MS-Compiler immer etwas pingeliger als die anderen. Weiß jemand, was der Standard dazu sagt?Moritz
-
Ne, vor allem bei templates hat er seine Macken...
-
ich weis auch nicht, was der standard sagt, aber das müsste eigentlich problemlos gehen, da der member ja relativ zu base* immer gleich liegt, er also konstant ist.
-
Nachdem ich eine Weile rumprobiert habe, bin ich auf folgenden (unschönen) Workaround gekommen, der aber nicht ganz funktioniert:
template <typename Base> class c1 { private: static int Base::* basevar; const Base* base; public: c1 (const Base* baddr, int* vaddr) : base (baddr) { basevar = reinterpret_cast <int Base::*> (reinterpret_cast <const Base*> (vaddr) - baddr); // das funktioniert irgendwie nicht, da man anscheinend nicht von ptrdiff_t nach int Base::* casten kann } int getBaseVar (void) { return (base->*basevar); } }; class c1test { private: int var; public: c1 <c1test> c1instance; c1test (void) : c1instance (this, &var), var (0) { } };
Da der (ohnehin konstante) pointer-to-member static ist, würde diese Lösung Instanzen dieser Klasse nicht vergrößern, wenn es nur funktionieren würde
.
Kennt jemand zu oben beschriebenem Problem eine Lösung? Kann man denn überhaupt etwas in einen pointer-to-member casten (sonst wäre die letzte und plattformunabhängigste Lösung Inline-ASM :()?Moritz
-
Da hab ich mal wieder den Wald vor lauter Bäumen nicht gesehen
...
Natürlich ist der einfachste Workaround folgender:
template <typename Base> class c1 { private: static int Base::* basevar; const Base* base; public: c1 (const Base* baddr, int Base::* vaddr) // einfach int Base::*-Pointer statt int*-Pointer übergeben :rolling_eyes: : base (baddr) { basevar = vaddr; // dann braucht man auch keinen reinterpret_cast } int getBaseVar (void) { return (base->*basevar); } }; template <typename Base> int Base::* c1::basevar; // nicht vergessen ;-) class c1test { private: int var; public: c1 <c1test> c1instance; c1test (void) : c1instance (this, &c1test::var), var (0) { } };
Moritz