Problem ze wskaźnikami na funkcje

0

(VS2017, GLFW, GLAD, OpenGL)

Posiadam taką klasę:

class Klasa
{
private:
    //składowe prywatne
public:
    void framebuffer_size_callback(GLFWwindow* win, int w, int h);
};

Definicja void framebuffer_size_callback(GLFWwindow* win, int w, int h);

void framebuffer_size_callback(GLFWwindow* win, int w, int h)
{
    glViewport(0, 0, w, h)
}

Następnie w innym fragmencie kodu chcę przekazać wskaźnik na tą funkcję do innej funkcji:

    glfwSetFramebufferSizeCallback(win /* jakaś zmienna wcześniej zadeklarowana*/, this->framebuffer_size_callback /* przy samym 
    framebuffer_size_callback wyskakuje inny błąd*/);

IntelliSense się przymyka, ale jak zaczynam kompilację, wyskakuje błąd:
"niestandardowa składnia; użyj znaku „&”, aby utworzyć wskaźnik do składowej"

O co chodzi? Funkcja framebuffer_size_callback() musi być składową klasy Klasa ponieważ korzysta z jej składowych, (niekoniecznie prywatnych) a przez parametry referencji do obiektu przekazać nie mogę bo mam ściśle określony prototyp.

0

Masz użyć

&Klasa::framebuffer_size_callback 

Przy czym jest to wskaźnik typu

void (Klasa::*)(GLFWwindow*, int, int)

a twoje api pewnie oczekuje

void(*)(GLFWwindow*, int, int)
0

Teraz kompilator krzyczy: GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow *,GLFWframebuffersizefun)”: nie można dokonać konwersji argumentu 2 z „void (__cdecl Klasa::* )(GLFWwindow *,int,int)” do „GLFWframebuffersizefun",

przy czym GLFWframebuffersizefun to: typedef void (*GLFWframebuffersizefun)(GLFWwindow*, int, int)

0

Czyli to co pisałem. Nie możesz przekazać niestatycznej funkcji klasy, bo to inny typ. Zmień ją w funkcję statyczną lub użyj funkcji wolnej.

0

Statyczna być nie może, bo metoda musi mieć dostęp do danych związanych z obiektem, nie z klasą. Z funkcją wolną tak samo. Jest jakiś sposób na przekazanie obiektu do tej funkcji inaczej niż przez argumenty?

0

Ustaw na swoim oknie user pointer za pomocą glfwSetWindowUserPointer(), a potem w callbacku go odzyskaj używając glfwGetWindowUserPointer()
https://www.glfw.org/docs/3.3[...]fc6026e690ab31a13f78bc9fd3651

0

"C++ have pointers to functions, but C++ programmers do not use them if they are sane" Uncle bob

Jednak to glfwSetFramebufferSizeCallback to jest API C https://www.glfw.org/docs/lat[...]b7c3366577daef18c0023e2a8591f

Teraz twoje framebuffer_size_callback to jest metoda, a nie funkcja! Efekt jest taki, że jako funkcja ma dodatkowy ukryty parametr this i dlatego nie może być być skonwertowana do typu akceptowanego przez glfwSetFramebufferSizeCallback.

Najprostsze rozwiązanie to uczynić framebuffer_size_callback metodą statyczną (brak parametry this).
Problemy zaczynają się, jeśli chcesz mieć dostęp do pól obiektu twojej klasy Klasa. Niestety glfwSetFramebufferSizeCallback nie dostarcza standardowego rozwiązania w postaci dowolnego kontekstu.

Jedyne znane mi rozwiązanie, jest brzydkie i straszne, dodać stan globalny, który zmapuje wskaźnik GLFWwindow * do wskaźnika twojej klasy.

Inne mniej paskudne, to niech twoja klasa dziedziczy po GLFWwindow, wtedy konwersja będzie możliwa:

class Klasa : public GLFWwindow
{
public:
      void framebuffer_size_callback(int, int); // może być potrzebne extern "C"  lub __cdecl
      static void framebuffer_size_callback2(GLFWwindow *self, int x, int  y) {
             static_cast<Klasa>(self)->framebuffer_size_callback(x, y);
      }

      void registerCallback() {
             glfwSetFramebufferSizeCallback(this, &Klasa::framebuffer_size_callback);
             //albo
             glfwSetFramebufferSizeCallback(this, &Klasa::framebuffer_size_callback2);
      }
};
0

Nie za bardzo rozumiem jak miałoby mi to pomóc w rozwiązaniu mojego problemu. Mógłbyś mi to bardziej wytłumaczyć? Uczę się właśnie OpenGLa.

2

glfwSetFramebufferSizeCallback nie oferuje możliwości przekazywania kontekstu. Jedyne miejsce, gdzie możesz to zrobić to obiekt GLFWindow, więc będzie to wyglądało jakoś tak:

glfwSetWindowUserPointer(win, this);
glfwSetFramebufferSizeCallback(win, &Klasa::framebuffer_size_callback);

A sama funkcja musi być wolna/statyczna:

/* static */
void Klasa::framebuffer_size_callback(GLFWwindow* win, int w, int h)
{
    Klasa* this_ = static_cast<Klasa*>(glfwGetWindowUserPointer(win));
    glViewport(0, 0, w, h)
}
0

Czyli funkcja glfwSetWindowUserPointer ustawia mi coś w rodzaju takiego kontenera na moje dane i GLFW ignoruje jego zawartość?

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0