Problem mit Templates für AutoBinding Mechanismen

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
snoob741
Beiträge: 76
Registriert: 03.04.2012, 22:36

Problem mit Templates für AutoBinding Mechanismen

Beitrag von snoob741 »

In meiner Engine benutze ich zur Realisierung von Shader-Parametern ein AutoBinding Mechanismus, der auf der folgenden Struktur basiert und es mir ermöglicht von beliebigen Objekten Methoden dynamisch zur Laufzeit mit beliebigen Rückgabewerten zu referenzieren:

Code: Alles auswählen

// Globales interface
class MethodBinding
 {
      public:
        MethodBinding(){}
        virtual ~MethodBinding() { }
        
        virtual void update(void) = 0;     
};

// Template für ein Single-Value Parameterupdate
 template <class ClassInstance, class BindingMethod>
    class ValueBinding : public MethodBinding
    {
    protected:
        typedef BindingMethod(ClassInstance::*Method)() const;    
    
    public:
    
        /**
	      @brief Create a new value binding.
        @throws brCore::brIllegalArgument exception if parameters are invalid.
	      @param parameter Reference to parent shader parameter which have to update.
        @param instance  The instance of the class containing the member method to bind.
        @param binding   The class method to bind (in the format '&class::method').  
        */
        ValueBinding(brShaderParameter* parameter, ClassInstance* instance, Method binding)
        {
            brCore::brAssert<brCore::brIllegalArgumentException>(parameter,
            "[brShaderParameter]::ValueBinding: The brShaderParameter is invalid!");
            
            brCore::brAssert<brCore::brIllegalArgumentException>(instance,
            "[brShaderParameter]::ValueBinding: The class instance is invalid!");
        
            m_parameter = parameter;
            m_instance  = instance;
            m_binding = binding;
        }
        
       	/** 
       	 @brief Calls the binding method to perform parameter value update.
       	 @throws brCore::brIllegalStateException if shader parameter reference is invalid 
        */
        virtual void update(void) override
        {
            brCore::brAssert<brCore::brIllegalStateException>(m_parameter,
            "[brShaderParameter]::ValueBinding:update: The brShaderParameter is invalid!");
            m_parameter->setValue((m_instance->*m_binding)());
            
            std::cout << "Value binding update called: " << m_parameter->getName() << std::endl;
        }
                                                                     
    protected:
        brShaderParameter* m_parameter;
        ClassInstance* m_instance;  
        Method m_binding;      
    };
Hierbei halte ich mir ein Pointer auf das Interface und erzeuge die entsprechende Instanz über folgende Template Funktion:

Code: Alles auswählen

 /** Reference to resolve build-in method binding*/   
 MethodBinding* m_method = nullptr;

template <class ClassInstance, class BindingMethod>
inline void brShaderParameter::bindValue(ClassInstance* instance, BindingMethod (ClassInstance::*Method)() const)
{
    m_method = new ValueBinding<ClassInstance, BindingMethod>(this, instance, Method); 
}  

// Beispiel für die Erzeugung
parameter->bindValue(&renderer->m_renderState, &brRenderState::getWorldViewMatrix); 
Klappt soweit hervorragend und ich kann so effektiv Shader-Parameter dynamisch aktualisieren, wie z.B. ModelViewProjectionMatrix usw. Nun will ich das ganze für Arrays ausbauen. Zur Einfachheit habe ich hierfür einfach das gleiche Template um eine zusätzlichen Counter erweitert, der ebenfalls über eine registrierte Methode dynamisch abgefragt werden soll:

Code: Alles auswählen

template <class ClassInstance, class BindingMethod>
    class ArrayBinding : public MethodBinding
    {
        typedef BindingMethod(ClassInstance::*Method)() const;
        typedef unsigned int(ClassInstance::*Count)() const;
            
    public:
        ArrayBinding(brShaderParameter* parameter, ClassInstance* instance, Method binding, Count count)
        {
            brCore::brAssert<brCore::brIllegalArgumentException>(parameter,
            "[brShaderParameter]::ValueBinding: The brShaderParameter is invalid!");
            
            brCore::brAssert<brCore::brIllegalArgumentException>(instance,
            "[brShaderParameter]::ValueBinding: The class instance is invalid!");
        
            m_parameter = parameter;
            m_instance  = instance;
            m_binding = binding;
            m_count = count;
            
            std::cout << "Array Binding performed" << m_parameter->getName() << std::endl;
            
        }
        
        void update(void) override
        {        
            brCore::brAssert<brCore::brIllegalStateException>(m_parameter,
            "[brShaderParameter]::ArrayBinding:update: The brShaderParameter is invalid!");
            m_parameter->setValue((m_instance->*m_binding)(), (m_instance->*m_count)());
            
            std::cout << "Array binding update called: " << m_parameter->getName() << std::endl;
        }
    
    private:
        brShaderParameter* m_parameter;
        ClassInstance* m_instance; 
        Method m_binding; 
        Count m_count;     
    };
Und hiermit gibt es aktuell Probleme. Ich Erzeuge das Objekt wie gehabt:

Code: Alles auswählen


template <class ClassInstance, class BindingMethod>
inline void brShaderParameter::bindArray(ClassInstance* instance,  BindingMethod (ClassInstance::*Method)() const, unsigned int (ClassInstance::*Count)() const)
{
    std::cout << "BindArray called and ArrayBinding instance created" << std::endl;
    m_method = new ArrayBinding<ClassInstance, BindingMethod>(this, instance, Method, Count); 
}  

// Beispiel
 parameter->bindArray(&renderer->m_renderState, &brRenderState::getDirectionalLightDirections, &brRenderState::getNumberOfDirectionalLights);
Klappt auch, die entsprechenden Funktionen und Konstruktoren werden wie gewünscht aufgerufen. Doch wenn ich nun irgendwo im Rendercode meinen üblichen
Aufruf zum Update aufrufe:

Code: Alles auswählen

    if(m_method != nullptr){
        m_method->update();    
    }    
Dann wird aus einem mir nicht erklärbaren Grund immer die Update-Methode vom ValueBinding Template ausgeführt, niemals vom ArrayBinding. Verstehe ich nicht, hab sogar versucht das ganze schon über Vererbung zu lösen, d.h. ArrayBinding von ValueBinding abzuleiten. Auch hier wird immer ValueBinding::update ausgeführt obwohl ich eine ArrayBinding Instanz erzeuge.

Leider läuft aktuell mein Linux nicht, so das ich nicht mit Codeblocks debuggen kann. Und unter Windows will aktuell Codeblocks nicht mit dem MinGW64 zusammenarbeiten. So dass ich grad ohne Debugger da stehe ... Aber eigentlich müsste es doch so korrekt sein oder habe ich irgend etwas übersehen?
snoob741
Beiträge: 76
Registriert: 03.04.2012, 22:36

Re: Problem mit Templates für AutoBinding Mechanismen

Beitrag von snoob741 »

Hab den Fehler gefunden. Liegt nicht am Template, hatte an anderer Stelle versehentlich den Aufruf der update-Methode auskommentiert. Daher kein Update ...
Sollte zusehen dass ich mein Linux wieder lauffähig bekomme, damit mir so etwas nicht noch einmal passiert :roll:
Antworten