Pointer innerhalb Klasse auf Memberfunktion
-
FrEEzE2046 schrieb:
Bei mir will die Syntax aber so noch nicht funktionieren. Kann da jemand was zu sagen?
Nein. Man könnte bestenfalls raten was da "so noch nicht funktioniert". Wenn du den Code postest, der nicht funktioniert (am besten mit der Fehlereldung zusammen), dann sind die Chancen gleich viel besser dass dir jeman helfen kann.
Siehe auch hier.
-
FrEEzE2046 schrieb:
Laut MSDN unterstützt das Visual Studio 2008 nach Installation des Visual C++ Feature Packs auch Variadic Templates
Da irrst Du Dich. Das was auf deren Webseite steht ist "nur" Dokumentation und kein kompilierbarer Code. Die haben dort "..." stehen, um zu zeigen, dass man tuple<> so benutzen kann, als wäre es ein variadisches Template. Es ist aber keins, weil sie die noch nicht unterstützen -- auch noch nicht in der aktuellsten Beta-Version.
Ich habe schon ein PDF von hier verlinkt, was genau beschreibt, wie versch. Dinge (function, tuple, ...) zur Zeit ohne variadische Templates implementiert werden und wie sich die Implementierung mit variadischen Templates stark vereinfachen lässt. Du hast es anscheinend nicht sorgfältig genug gelesen.
Nebenbei: Hier gibt's ein paar nette Artikel zur Benutzung von Threads unter C++0x.
-
Sebastian Pizer schrieb:
Ich habe schon ein PDF von hier verlinkt, was genau beschreibt, wie versch. Dinge (function, tuple, ...) zur Zeit ohne variadische Templates implementiert werden
Wenn du das hier meinst:
Doch das habe ich mir sorgfältig angeschaut, aber auch dort benutzen sie doch '...'
siehe:
template<typename... Args> struct count;Oder meinstest du ein anderes PDF?
-
@FrEEzE2046,
Am Anfang des PDFs wird aber erklärt, wie man es bisher in den C++ Bibliotheken gemacht hat. Und genau so macht es auch Boost.Function, Boost.Bind usw.
Zudem wird auf Boost.Preprocessor verwiesen, was man zur Hilfe heranziehen kann, was bei Boost für das Simulieren von variadic templates auch gemacht wird.Grundsätzlich steht alles da am Anfang von Kapitel 2. Es ist sehr kurz gehalten, aber fasst es eigentlich vollständig zusammen.
Grüssli
-
Sorry für den Doppelpost, aber da schon einige Zeit vergangen ist, wollte ich nicht nur ein Edit machen. Hier noch ein kurzes dahingerotztes Beispiel

#include <iostream> #include <boost/preprocessor.hpp> #define MY_MACRO_TEMPLATE_TYPES(z, n, data) , typename T##n #define MY_MACRO_TEMPLATE_ARGS(z, n, data) , T##n const& arg##n #define MY_MACRO_TEMPLATE_OUTPUT(z, n, data) << arg##n #define MY_MACRO_PRINT_FUNCTION(z, n, data) \ template<typename T0 BOOST_PP_REPEAT_FROM_TO(1, n, MY_MACRO_TEMPLATE_TYPES, data)>\ void print(T0 const& arg0 BOOST_PP_REPEAT_FROM_TO(1, n, MY_MACRO_TEMPLATE_ARGS, data)) \ { \ std::cout BOOST_PP_REPEAT(n, MY_MACRO_TEMPLATE_OUTPUT, data) ;\ } \ #define MY_MACRO_CREATE_PRINT_FUNCTIONS(n) \ BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(n), MY_MACRO_PRINT_FUNCTION, _) MY_MACRO_CREATE_PRINT_FUNCTIONS(10) int main() { print("Hello", " World", '!', '\n', "Test: ", 443, '\n'); return 0; }Die maximale Anzahl an Parametern ist 10. Also quasi Variadic Templates beschränkt auf 10 Parametern. Das ganze präsentiert an einer
printFunktion. Sieht hässlich aus, nicht?
Variadic Templates aus C++0x werden diese Hässlichkeiten hoffentlich entfernen können
Grüssli
-
Ich steig einfach nicht dahinter, wie man die Template-Argumente zunächst auf "typename Signature" begrenzt und dann intern in die Spezialisierungen aufsplittet.
Mir ist klar, dass das mit irgendwelchen Makro-Verschachtelungen geschieht, aber ich versteh noch nicht wie. Würde mich aber sehr interessieren.
Das einzige was ich in der Richtung hinbekomme ist sowas hier:
#define PP_REPEAT_1( param ) param ## 0 #define PP_REPEAT_2( param ) param ## 0, param ## 1 #define PP_REPEAT_3( param ) param ## 0, param ## 1, param ## 2 #define ENUM_PARAMS( count, param ) PP_REPEAT_##count( param ) template<ENUM_PARAMS( 3, typename T )> class function {};Das ändert aber nichts daran, dass ich
function<int, int, int> f;Benutzen muss. Wie kann das anders gelöst werden?
-
Hier mal ein wenig Beispielcode (Achtung, sehr viele wichtige Dinge wie Kopierkonstruktoren usw. usf. wurden weggelassen):
#include <memory> template<typename T> struct FunctorImpl; template<typename R> struct FunctorImpl<R()> { typedef R ResultType; virtual R call() const; virtual FunctorImpl* clone() const; }; template<typename R, typename P0> struct FunctorImpl<R(P0)> { typedef R ResultType; typedef P0 Parameter0; virtual R call(Parameter0) const; virtual FunctorImpl* clone() const; }; template<typename R, typename P0, typename P1> struct FunctorImpl<R(P0, P1)> { typedef R ResultType; typedef P0 Parameter0; typedef P1 Parameter1; virtual R call(Parameter0, Parameter1) const = 0; virtual FunctorImpl* clone() const = 0; }; // usw. halt mit Makros aktuell template<typename ImplT, typename FuncT> struct FunctorHandler : ImplT { private: FuncT m_func; public: FunctorHandler(FuncT func) : m_func(func) { } public: typename ImplT::ResultType call() const { return m_func(); } typename ImplT::ResultType call(typename ImplT::Parameter0 p0) const { return m_func(p0); } typename ImplT::ResultType call(typename ImplT::Parameter0 p0, typename ImplT::Parameter1 p1) const { return m_func(p0, p1); } // usw. mit Makros FunctorHandler* clone() const { return new FunctorHandler(*this); } }; template<typename T> struct Functor { private: typedef FunctorImpl<T> Impl; std::auto_ptr<Impl> m_impl; public: template<typename FuncT> Functor(FuncT func) : m_impl(new FunctorHandler<Impl, FuncT>(func)) { } public: typename Impl::ResultType operator ()() const { return m_impl->call(); } typename Impl::ResultType operator ()(typename Impl::Parameter0 p0) const { return m_impl->call(p0); } typename Impl::ResultType operator ()(typename Impl::Parameter0 p0, typename Impl::Parameter1 p1) const { return m_impl->call(p0, p1); } // usw. mit Makros }; // ... #include <iostream> int foo(int x, double y) { return static_cast<int>(x * y); } int main() { Functor<int(int, double)> functor(&foo); return functor(4, 22.3); }Es gibt auch noch andere Vorgehensweisen, habe das jetzt nur so mehr oder weniger schnell aus dem Kopf zusammengebaut. Ich hoffe allerdings, dass es das eigentliche Prinzip erklärt.
Grüssli
-
FrEEzE2046 schrieb:
Das ändert aber nichts daran, dass ich
function<int, int, int> f;Benutzen muss. Wie kann das anders gelöst werden?
Defaultparameter

EDIT:
Ja, camper hat natürlich recht. Weiss auch nicht wie ich darauf gekommen bin, dass man Klassentemplates überladen könnte.
-
LordJaxom schrieb:
Kurz: Das liegt daran, dass Du ein Template mit drei Parametern erzeugst. Boost.Function hat aber mehrere Templates, eines mit 0, eines mit einem, eines mit zwei, ...., eines mit zehn Parametern. Die Templates heissen alle gleich, weshalb es für Dich so aussieht als wäre es variadic.
Zudem gäbe es noch die Möglichkeit für alle Parameter Defaults anzugeben.
Ja, dass ist mir schon klar. Entschuldige, ich hab mich wieder unpräzise ausgedrückt.
Beispiel:
struct nil; template<typename R = nil, typename T0 = nil, typename T1 = nil, typename T2 = nil> class function; template<> class function<> {}; template<typename R> class function<R> {}; template<typename R, typename T0> class function<R, T0> {}; template<typename R, typename T0, typename T1> class function<R, T0, T1> {}; // Trotzdem: function<int, int> f1; function<int, int, int> f2;Ich frage mich halt, wie es gemacht wird einen Funktionstyp anzugeben (z.B. void (int, double) und den dann intern dem Template:
template<typename R = nil /*void*/, typename T0 = nil /*int*/, typename T1 = nil /*double*/> class function.zuzuordnen.
-
Klassentemplates können nicht überladen werden.
-
FrEEzE2046 schrieb:
Ich frage mich halt, wie es gemacht wird einen Funktionstyp anzugeben (z.B. void (int, double) und den dann intern dem Template:
template<typename R = nil /*void*/, typename T0 = nil /*int*/, typename T1 = nil /*double*/> class function.zuzuordnen.
Templatespezialisierungen, so wie Dravere es vor meinem Unsinnsposting gezeigt hat.
-
camper schrieb:
Klassentemplates können nicht überladen werden.
Hat wer überhaupt gesagt?
Ich habe mal die syntaktischen Fehler aus meinem Posting beseitigt. Danke an alle, ich hab jetzt verstanden, wie`s gemacht wird
-
FrEEzE2046 schrieb:
camper schrieb:
Klassentemplates können nicht überladen werden.
Hat wer überhaupt gesagt?
Ich

-
Hallo mal wieder,
du hast so schön geschrieben: "usw. mit Makros ..."
Wie genau geht
s denn nun mit Makros weiter? ;-) So kann mans ja nicht implementieren, sonst bekommt man ja die schöne Meldung:'void Functor<T>::operator ()(int) const' : member function already defined or declared... sobald man eine Funktion übergeben will, die weniger Parameter als (in deinem Beispiel:) 2 hat.
Wie genau kann man das mit Makros lösen?
-
Oh, habe ich etwas vergessen gehabt. War wie gesagt aus dem Kopf heraus. Den Code ein wenig modifiziert:
#include <memory> struct EmptyType { }; template < typename P0 = EmptyType, typename P1 = EmptyType, typename P2 = EmptyType // usw. bis maximale Anzahle Parameter > struct Parameters { typedef P0 Type0; typedef P1 Type1; typedef P2 Type2; // usw. bis maximale Anzahle Parameter // Beide Listen kann man auch mit Makros bauen lassen, // somit auch die ganze Klasse ... }; template<typename T> struct FunctorImpl; template<typename R> struct FunctorImpl<R()> { typedef R ResultType; typedef Parameters<> Parameters; virtual R call() const = 0; virtual FunctorImpl* clone() const = 0; }; template<typename R, typename P0> struct FunctorImpl<R(P0)> { typedef R ResultType; typedef Parameters<P0> Parameters; virtual R call(P0) const = 0; virtual FunctorImpl* clone() const = 0; }; template<typename R, typename P0, typename P1> struct FunctorImpl<R(P0, P1)> { typedef R ResultType; typedef Parameters<P0, P1> Parameters; virtual R call(P0, P1) const = 0; virtual FunctorImpl* clone() const = 0; }; // usw. halt mit Makros aktuell template<typename ImplT, typename FuncT> struct FunctorHandler : ImplT { private: FuncT m_func; public: FunctorHandler(FuncT func) : m_func(func) { } public: typename ImplT::ResultType call() const { return m_func(); } typename ImplT::ResultType call(typename ImplT::Parameters::Type0 p0) const { return m_func(p0); } typename ImplT::ResultType call(typename ImplT::Parameters::Type0 p0, typename ImplT::Parameters::Type1 p1) const { return m_func(p0, p1); } // usw. mit Makros FunctorHandler* clone() const { return new FunctorHandler(*this); } }; template<typename T> struct Functor { private: typedef FunctorImpl<T> Impl; std::auto_ptr<Impl> m_impl; public: template<typename FuncT> Functor(FuncT func) : m_impl(new FunctorHandler<Impl, FuncT>(func)) { } public: typename Impl::ResultType operator ()() const { return m_impl->call(); } typename Impl::ResultType operator ()(typename Impl::Parameters::Type0 p0) const { return m_impl->call(p0); } typename Impl::ResultType operator ()(typename Impl::Parameters::Type0 p0, typename Impl::Parameters::Type1 p1) const { return m_impl->call(p0, p1); } // usw. mit Makros }; // ... #include <iostream> int foo() { return 0; } int main() { Functor<int()> functor(&foo); std::cout << functor() << std::endl; return 0; }Jetzt geht es auch mit weniger. Hmmm, die Verwendung von Typlisten wäre hier ziemlich von Vorteil, aber bin jetzt zu Faul dieses Zeug auch noch hinzuschreiben ...
Wesentlicher Unterschied zur vorherigen Version ist die StrukturParameters. Problem war natürlich, dass nicht alle die maximale Parameter Zahl aufweisen, daher müssen diese mit demEmptyTypebesetzt werden. Die StrukturParametersdient zur Vereinfachung. Über eine Typliste hätte man das ganze wohl noch mehr vereinfachen können.Die Makros selber sind nur wichtig, wenn du mehr als 2 Parameter aktzeptieren möchtest. Wie das dann funktioniert, habe ich schon weiter vorne beschrieben mit der
printFunktion. Wenn du wirklich beide Vorgehen vollständig verstanden hast, solltest du in der Lage sein, diese zu kombininieren.Aber ich glaube, ich empfehle hier langsam lieber das folgende Buch:
Modern C++ Design von Andrei Alexandrescu
Modern C++ Design | ISBN: 0201704315Dort kommen solche Themen dran und werden ausführlich erklärt und nicht nur auf die Schnelle aus dem Kopf heraus

Grüssli