Pregunta

Di que tengo:

void Render(void(*Call)())
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

Esto está bien siempre y cuando la función que quiero usar para renderizar sea una función o un static función miembro:

Render(MainMenuRender);
Render(MainMenu::Render);

Sin embargo, realmente quiero poder usar un método de clase también, ya que en la mayoría de los casos la función de representación querrá acceder a las variables miembro, y prefiero no hacer que la instancia de clase sea global, por ejemplo.

Render(MainMenu->Render);

Sin embargo, realmente no tengo idea de cómo hacer esto y todavía permito funciones y static funciones miembro que se utilizarán.

¿Fue útil?

Solución

Hay muchas formas de despellejar a este gato, incluidas las plantillas.Mi favorito es Función de impulso ya que he descubierto que es el más flexible a largo plazo.Lea también sobre Impulsar.bind para vincular funciones miembro, así como muchos otros trucos.

Se vería así:

#include <boost/bind.hpp>
#include <boost/function.hpp>

void Render(boost::function0<void> Call)
{
    // as before...
}

Render(boost::bind(&MainMenu::Render, myMainMenuInstance));

Otros consejos

Puedes hacer una función contenedora. void Wrap(T *t) eso solo llama t->Call() y tiene Render tomar tal función junto con un objeto.Eso es:

void Wrap(T *t)
{
  t->Call();
}

void Render(void (*f)(T *), T *t)
{
  ...
  f(t);
  ...
}

Lo hice una vez definiendo una función global "Llamar" que acepta un puntero a su instancia como miembro

void CallRender(myclass *Instance)
{
  Instance->Render();
}

Entonces el renderizado se convierte en:

void Render(void (*Call)(myclass*), myclass* Instance)
{
  ...
  Call(Instance);
  ...
}

Y tu llamado a renderizar es:

Render(CallRender, &MainMenu);

Sé que es feo, pero funcionó para mí (estaba usando pthreads)

No puede llamar a una función miembro desde un puntero a menos que también tenga una referencia al objeto.Por ejemplo:

((object).*(ptrToMember))

Por lo tanto, no podrá lograr esto sin cambiar la firma de su método de renderizado. Este El artículo explica por qué esto es generalmente una mala idea.

Una mejor manera podría ser definir una interfaz "Renderizador" que sus clases que tienen métodos de renderizado puedan implementar y que sea el tipo de parámetro de su método de renderizado principal.Luego podría escribir una implementación "StaticCaller" para admitir la llamada de sus métodos estáticos por referencia.

por ejemplo (Mi C++ está muy oxidado, tampoco lo he compilado).



void Render(IRenderer *Renderer)
{
    D3dDevice->BeginScene();
    Renderer->Render();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

// The "interface"
public class IRenderer 
{
public:
    virtual void Render();
};

public class StaticCaller: public IRenderer
{
    void (*Call)();
public:

    StaticCaller((*Call)())
    {
        this->Call = Call;
    }

    void Render()
    {
        Call();
    }
};

Todo esto es bastante repetitivo, pero debería facilitar la lectura.

Puede declarar un puntero de función a una función miembro de la clase T usando:

typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
FUNCTIONPOINTERTYPE function;

Y invocarlo como:

T* t;
FUNCTIONPOINTERTYPE function;
(t->*function)(args..);

Extrapolar esto a un sistema de curry útil con argumentos variables, tipos, valores de retorno, etc., es monótono y molesto.He escuchado cosas buenas sobre la biblioteca de impulso antes mencionada, por lo que recomendaría investigarla antes de hacer algo drástico.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top