c++ 将函数从另一个类传递到另一个函数

qoefvg9y  于 2022-12-15  发布在  其他
关注(0)|答案(1)|浏览(169)

X11库中的XSetErrorHandler()函数需要一个函数。
如果我在main()[in main.cpp]上面定义了一个函数,比如:

int catch_error(Display *disp, XErrorEvent *xe){return 0;}

然后我做以下操作:

XSetErrorHandler(catch_error);

它起作用了。
如何将catch_error函数放在名为WindowHandler的类中,然后将其传递给XSetErrorHandler();
我尝试了以下方法:

WindowHandler window_handler = new WindowHandler();
XSetErrorHandler(WindowHandler::catch_error);
XSetErrorHandler(window_handler->catch_error);
XSetErrorHandler((*window_handler).catch_error);


错误1)类型为“int(WindowHandler::*)(Display *disp,XErrorEvent *xe)”的参数与类型为“XErrorHandler”的参数不兼容
2)和3)指向绑定函数的指针只能用于调用该函数
谢谢你的帮忙!

vuv7lop3

vuv7lop31#

问题是非静态成员函数需要一个隐式的第一个参数,这个参数是指向类 (在本例中是WindowHandler 的指针或引用,所以如果我们考虑到隐式参数,那么它的签名与自由的catch_error函数不同。
我不知道XSetErrorHandler是如何声明的,但是这个函数可以接受函子:在这种情况下,可以将对WindowHandler::catch_error的调用 Package 在一个lambda表达式中,该表达式捕获指向WindowHandler示例的指针。

WindowHandler* window_handler = new WindowHandler();
XSetErrorHandler(
    [window_handler](Display *disp, XErrorEvent *xe) {
        return window_handler->catch_error(disp, xe);
    }
);
delete window_handler; // if you really must use new (why would you ever?), please also delete.

下面是关于指向成员函数的指针的一些进一步的阅读:https://isocpp.org/wiki/faq/pointers-to-members

编辑:

我刚刚意识到,XSetErrorHandler接受函子,而只接受函数指针https://tronche.com/gui/x/xlib/event-handling/protocol-errors/XSetErrorHandler.html。在这种情况下,WindowHandler::catch_error必须是静态的。如果lambda没有捕获任何内容,则只能将其视为函数指针。
如果你真的想在WindowHandler的一个成员中捕获error_flag,我看到的唯一选择是拥有WindowHandler * 的一个全局示例(所谓的单例)*,然后静态catch_error函数可以设置这个单例的成员,不需要隐式的this参数。
注意,不鼓励使用全局变量和单例变量,如果可能的话,应该避免使用。在某些情况下,这是不可能的。在这些情况下,通常需要日志记录和错误处理。

#include <iostream>
#include <memory>

struct Display {};
struct XErrorEvent {};

void XSetErrorHandler(
      int (*handler)(Display *, XErrorEvent *)
) {}

class WindowHandler 
{
private:
    // constructor is private: No other class should be allowed to construct instances
    WindowHandler() = default;

    int catch_error_impl(Display*, XErrorEvent*) {
        std::cout << "Error happened\n";
        error_flag = 1;
        return 0;
    }  

public:
    // don't copy or move a singleton
    WindowHandler(WindowHandler const&) = delete;
    WindowHandler(WindowHandler&&) = delete;

    // the global WindowHandler singleton gets instantiated the first time the get_instance_ptr function is called
    static WindowHandler* get_instance_ptr() {
        // calling new in the argument of unique_ptr ctor is ok. memory is freed when the dtor is called
        static auto handler = std::unique_ptr<WindowHandler>(new WindowHandler());
        return handler.get();
    }

    static int catch_error(Display* disp, XErrorEvent* xe) {
        return get_instance_ptr()->catch_error_impl(disp, xe);
    } 

    int error_flag {0};
};

int main()
{
    XSetErrorHandler(WindowHandler::catch_error);
    std::cout << WindowHandler::get_instance_ptr()->error_flag << std::endl;
}

https://godbolt.org/z/MTWcfK3bs

相关问题