Pointer auf jede Template-Variation
-
Ja, ist eine ganz gute Idee. Danke schon mal. Hätte man auch drauf kommen können, aber ich dachte es gibt einen besseren Weg.
Normalerweiße definiere ich für solche Dinge einen Dummy-Typen. Das ist hier aber leider nicht möglich, da ja die Template-Argumente das Member verändern.
-
FrEEzE2046 schrieb:
Ja, ist eine ganz gute Idee.
das ist genau die Idee, die dir SP und unskilled nahebringen wollten

-
pumuckl schrieb:
FrEEzE2046 schrieb:
Ja, ist eine ganz gute Idee.
das ist genau die Idee, die dir SP und unskilled nahebringen wollten

Ja, da dachte ich er will auf etwas anderes heraus.
Was mir jetzt noch fehlt ist eine Möglichkeit zu prüfen ob ein bestimmtest Template-Argument "void" ist. Eine Spezialisierung hilft mir nur bedingt.
-
Sagen dir type traits irgendetwas? Der folgende Code ist nur eine technische Lösung, vielleicht ist ein anderer Ansatz wie (partielle) Spezialisierung möglich?
template<typename T> struct type_traits { enum { IsVoid = false }; }; template<> struct type_traits<void> { enum { IsVoid = true }; }; template<typename T> void somefunc( T& op ) { if( true == type_traits<T>::IsVoid ) { // T ist vom Typ void } else { // T ist kein void } };
-
DocShoe schrieb:
Sagen dir type traits irgendetwas? Der folgende Code ist nur eine technische Lösung, vielleicht ist ein anderer Ansatz wie (partielle) Spezialisierung möglich?
Das Problem ist folgendes:
Die Klasse selbst bekommt einen Funktionstypen übergeben, daher ist ein einfaches überprüfen auf void (durch Spezialisierung) nicht möglich. Innerhalb der Klasse komme ich jedoch an den Return-Typ des Funktionstypen dran.Ich könnte jetzt per type trait eben überprüfen, ob es void ist oder nicht und je nachdem etwas anderes ausführen. Leider benötige ich jedoch auch eine Variable von diesem Typ und einen "void" Typen deklariert er nicht.
Ich denke ich werde einfach einen Pointer verwenden, für den ich mir dann dynamisch Speicher hole, wenn es nicht void ist.
btw. Man muss nicht explizit auf true prüfen

EDIT:
Leider mag der Compiler dass nicht. Er sagt dass er keine void Objekte allokieren kann ... dass das nie passieren kann kann er ja nicht wissen. Mmmh, andere Lösung?EDIT2:
So lässt er sich für die Allokierung austricksen:this->_ResultValue = reinterpret_cast<LP_RESULT>(new BYTE[sizeof(RESULT)]());Aber die Dereferenzierung passt ihm halt einfach nicht.
-
FrEEzE2046 schrieb:
Das Problem ist [...]
dass Du scheinbar die falschen Fragen stellst, wenn Dir die Antworten auf Deine Fragen nicht weiterhelfen.
Gruß,
SP
-
Sebastian Pizer schrieb:
dass Du scheinbar die falschen Fragen stellst, wenn Dir die Antworten auf Deine Fragen nicht weiterhelfen.
Stimmt. Die Antwort hat mir aber dennoch weitergeholfen. Ich habe es jetzt so gelöst (ist aber auf gar keinen Fall final und auch noch ungetestet)
template<typename T> struct type_traits { enum { IsVoid = false }; typedef T TYPE; static const size_t Size = sizeof(T); }; template<> struct type_traits<void> { enum { IsVoid = true }; typedef bool TYPE; static const size_t Size = 0; }; virtual void _Call(void) override { if( !type_traits<RESULT>::IsVoid ) { size_t nSize = type_traits<RESULT>::Size; this->_ResultValue = new BYTE[nSize](); LPVOID MemberAddress = reinterpret_cast<LPVOID>(&this->_function); typedef RESULT (function<Signature>::*LP_FUNCTION)(void) const; LP_FUNCTION lpFunction = &function<Signature>::operator (); ASM { [asm] push esi push edi mov ecx, MemberAddress call lpFunction mov esi, DWORD PTR [_ResultValue] mov edi, eax mov ecx, nSize repnz movsb pop edi pop esi[/asm] } } }
-
FrEEzE2046 schrieb:
[...]Was soll das denn? Willst Du das bei DailyWTF einreichen?
Ich habe das Gefühl, dass das, was Du machen willst, viel einfacher und vor allem viel eleganter geht. Du bist auf dem besten Weg, Dir die Beine abzuschießen.
Gruß,
SP
-
Sebastian Pizer schrieb:
Ich habe das Gefühl, dass das, was Du machen willst, viel einfacher und vor allem viel eleganter geht. Du bist auf dem besten Weg, Dir die Beine abzuschießen.
Wenn ich das Gefühl nicht auch gehabt hätte, hätte ich nicht gefragt. Aber es ist nur halb so schlimm wie es aussieht. Das Problem ist, dass ich innerhalb von einem Thread den Rückgabewert der darin aufgerufenen Funktion haben möchte.
Da dieser jedoch Template-Argument abhängig ist, kann es jeder beliebige Typ sein. Mir fällt da keine bessere Variante ein und vor allem funktioniert es.
So jedenfalls:
push esi push edi push ebx mov ebx, ecx mov ecx, [MemberAddress] call lpFunction mov ecx, ebx lea edi, [ecx]._ResultValue mov edi, [edi] push eax mov esi, esp mov ecx, nSize repnz movsb pop eax pop ebx pop edi pop esi
-
FrEEzE2046 schrieb:
Wenn ich das Gefühl nicht auch gehabt hätte, hätte ich nicht gefragt.
Und warum stellst Du dann so komische Fragen, die mit Deinem Problem gar nichts zu tun haben? Man (zumindest ich) weiß immer noch nicht, was Du eigentlich machen willst. Irgendwas mit Threads. Irgendwas mit Template-Parametern für Rückgabetypen von Funktionen. Das reicht aber nicht aus, um Verbesserungsvorschläge geben zu können.
Wenn Du mit dem Assembler-Gefrickel (
) zufrieden bist, ist ja alles i.O. :pGruß,
SP
-
Wieso weiß man nicht was ich machen will?
Meine Anfangs Frage wurde doch beantwortet. Ich habe es mit einer Interface-Klasse inkl. der virtuellen Methode die den call macht gelöst.
Alles weitere war jetzt ja nur eine neue Frage von mir, für die ich keinen neuen Thread aufmachen wollte. Die Frage war, wie ich ein Template-Argument auf void prüfe. Auch das ist erledigt und meine Lösung habe ich gepostet.
Wegen dem "Assembler-Gefrickel":
Wie hättest du es denn gelöst? Worum es exakt geht? Es existiert eine Thread-Funktion vom Typ unsigned long (__stdcall)(void*). Innerhalb dieser Thread-Funktion wird eine weitere FUnktion aufgerufen deren Rückgabewert ich benötige. Standardmäßig würde ich der Thread-Funktion nun also einen Pointer auf den Result übergeben, dessen Dereferenzierung ich dann die Funktion zuweise. Das geht aber nicht, da der Rückgabewert von der inneren Funktion von den Template-Argumenten abhängig ist. Ich habe also keine Ahnung von welchem Typ der Result sein soll, also wird dass so schon mal nichts. Da der Return-Wert bei einer __cdecl Funktion aber immer im EAX Register liegt (insofern kein Double oder anderer 8 Byte Typ, dann sieht's anders aus) ist das wohl schon mal ein Ansatz. Ist aber immer noch Scheiße.Ich habe schon eine weitaus bessere Variante. Ich werde sie heute Abend posten.
EDIT:
typename type_traits<RESULT>::TYPE _ResultValue; virtual void _Call(void) override { if( !type_traits<RESULT>::IsVoid ) { this->_ResultValue = this->_function(); } else { this->_function(); } }TYPE is immer der gleiche Typ wie RESULT; außer wenn RESULT void ist, dann ist TYPE bool. Somit ist es immer eine gültige Deklaration.
Hat immer noch das Problem, dass der Compiler keien Ahnung davon hat, dass das Code-Segment welches true zurückliefert nie ausgeführt wird, wenn RESULT void ist. Daher verweigert er den Dienst.
EDIT2:
Ich denke so ist es ganz gut gelöst:
template<typename Signature, typename Return> struct function_wrapper abstract { static void HandleReturn(Klasse<Signature>* Instance, Return* ReturnValue) { if( (ReturnValue != NULL) && (Instance != NULL) ) *ReturnValue = Instance->_function(); } }; template<typename Signature> struct function_wrapper<Signature, void> abstract { static void HandleReturn(Klasse<Signature>* Instance, void* ReturnValue) { if( Instance != NULL ) Instance->_function(); } }; template<typename Signature> class Klasse sealed { private: virtual void _Call(void) override { function_wrapper<Signature, RESULT>::HandleReturn(this, &this->_ResultValue); } template<typename Signature, typename Return> friend struct function_wrapper; };