Dynamische Parameterliste mit Templates beim definieren von operator()



  • Genau für diesen Anwendungsfall gibt es in der C++11-Standardbibliothek die Lösung:

    namespace hook
    {
        auto endscene = std::bind(hook_func, 42); // bindet die Zahl 42 an das erste Argument von hook_func
        auto middlescene = std::bind(hook_func, 43);
        ...
    }
    

    Der Aufruf ist dann ganz normal wie eine normale Funktion:

    auto result = endscene( /* evtl. andere Argumente */ );
    


  • bind klingt interessant, allerdings möchte ich die 42 nicht an hook_func binden, sondern an den Konstruktor von D3D_Hook. Sowas ist nicht zufällig auch möglich?



  • Aber dann musst du wieder

    D3D_Hook_EndScene pEndScene(...);
    
    pEndScene.call_original(...)
    

    schreiben, was du nicht wolltest?



  • Ich sollte vielleicht noch erwähnen dass im Gegensatz zu den Abgeleiteten Klassen der Konstruktor der Basisklasse nicht leer ist, sondern etwas macht. Die Basisklasse brauch ich also in jedem Fall.

    func_hook ist ein Callback den der User reinwirft. Die Funktion selbst hat mit der zahl 42 nix am Hut, außer dass der Konstruktor der Basisklasse anhand der Zahl entscheidet, welche Adresse der Zeiger bekommt.



  • Was mir dabei jedoch Probleme macht, ist die Parameterliste beim definieren von operator() in der Basisklasse. Kann ich die irgendwie vom Template setzen lassen oder ist das, was ich da vor habe gar nicht möglich?

    Seit C++11 ist das wunderbar möglich. Mit variadic templates und perfect forwarding:

    // Helfer-Makro
    #define AUTO_RETURN(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); }
    
    template <typename D3D_Func_type>
    class D3D_Hook
    {
    public:
        D3D_Func_type call_original; // <--- Funktionszeiger
    
        template<typename ... ArgTs>
        auto operator()(ArgTs&&... args) AUTO_RETURN( call_original( std::forward<ArgTs>(args)...) )
    };
    


  • Hey danke sieht vielversprechend aus. Mein Compiler (Visual Studio 2010) meckert leider bei dem Source, was auch kein Wunder ist, da der c++11 Standard erst 2011 erschien.

    Werde mir den Source mal auskommentiert reinpasten und bei Gelegenheit versuchen nen c++11 Compiler für visual studio 2010 aufzutreiben.
    Kann man eigentlich den Compiler von visual Studio 2012 mit 2010 verwenden? Hab zwar ne Studentenlizenz dafür aber ich kann mich ich mit Windows 8 und VS2012 noch nicht so recht anfreunden.



  • Du koenntest durchaus den Compi von VS2012 mit samt seiner erweiterten Libraries und Header in die entsprechenden VS2010-Verzeichnisse kopieren und damit weiter arbeiten -- theoretisch. Praktisch allerdings kannst du da einiges falsch machen und dir VS zerschiessen. Ich wuerd's jedenfalls nicht empfehlen.
    Nutz einfach VS2012. SuppressUpperCaseConversion zu 1 in Registry-Schluessel xyz und die GUI schreit dich nicht mehr an; ab Update 1 oder 2 gibt's sogar das alte VS2010-Farbschema wieder. Wenn du VS Professional hast, kannst du mit dem AddIn VS Color Theme Editor sogar noch mehr rumdoktern, bis es dir gefaellt.
    Und es laeuft auch auf Win7. Zumal du dich nicht "anfreunden" musst, da der Arbeitsablauf in 99% der Faelle der gleiche wie in VS 2010 ist



  • Genau, was mich störte waren diese Uppercase-Menüs, und dass die Menüs nicht mehr klar voneinander getrennt sind, also alles grau ineinander überläuft. Das finde ich unübersichtlich.

    Wenn ich mir VS2012 allerdings so zurechtfrickeln kann, dass es wie 2010 aussieht, steige ich gerne um. Hab damals allerdings auch den Release Candidate benutzt. Werds mir nochmal bei Dreamsparc saugen und mein Glück versuchen. Vielen Dank für die Infos. 🙂

    edit:
    Hab in der Studilizenz sogar die Ultimate Edition. 🙂



  • Stephan++ schrieb:

    Wenn ich mir VS2012 allerdings so zurechtfrickeln kann, dass es wie 2010 aussieht, steige ich gerne um.

    Kannst du. Du brauchst nur:
    1. http://stackoverflow.com/questions/10859173/how-to-disable-all-caps-menu-titles-in-visual-studio-2012-rc
    2. http://visualstudiogallery.msdn.microsoft.com/366ad100-0003-4c9a-81a8-337d4e7ace05



  • So, habs nun installiert.

    Visual Studio 2012 wollte zunächst genauso wenig wie 2010 compilen, da es mit dem variadic templates nichts anfangen konnte. Die installation von Service Pack 3 brachte auch nix. Allerdings ein uralter Patch vom November enthällt einen Compiler, der mit variadic templates umgehen kann:
    Download: http://www.microsoft.com/en-us/download/confirmation.aspx?id=35515
    Finds echt komisch, dass der compiler nicht im SP3 enthalten ist...
    Ein weiteres Problem was ich nach der Installation von VS2012 bekam war, dass VS2010 nicht mehr kompilieren wollte. Nach Installation von SP1 gings aber wieder.

    Jedenfalls wirft mir der Compiler nun folgenden Fehler:

    error C2893: Failed to specialize function template 'unknown-type D3D_Hook<EndScene_t>::operator ()(ArgTs &&...)'
    With the following template arguments:
    'LPDIRECT3DDEVICE9 &'

    Das Ganze passiert beim Aufrufen des () operators:

    // Hier nochmal die Funktionszeiger definition
    HRESULT __stdcall EndScene(LPDIRECT3DDEVICE9 pDevice); 
    typedef HRESULT(__stdcall* EndScene_t)(LPDIRECT3DDEVICE9);
    ...
    
    D3D_Hook_EndScene pEndScene(hkEndScene);
    
    pEndScene(pDevice); // <--- hier krachts
    ...
    

    Um ehrlich zu sein verstehe ich den Code von Sone nicht zu 100% aber ich bin nochmal alles durchgegangen und theoretisch sind alle Typen zur Kompilierzeit bekannt. Die Parameter werden jedenfalls schon mal richtig erkannt und eingesetzt.

    Folgende Zeilen interpretiere ich so:

    #define AUTO_RETURN(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } 
    
    auto operator()(ArgTs&&... args) AUTO_RETURN( call_original( std::forward<ArgTs>(args)...) )
    

    operator() bekommt eine variable argumentliste und einen noch nicht definierten rückgabewert. Die Argumente werden beim Aufruf vom Makro aus operator() in call_original() weitergereicht und der Typ des Rückgabewerts von call_original() bekommt auch operator().
    Mich wundert hierbei, dass der Kompiler ausgerechnet beim Aufruf von pEndScene(pDevice) meckert, da zu dem Zeitpunkt der Rückgabewert lange bekannt ist, da im Funktionszeiger definiert!? 😕


Anmelden zum Antworten