我可以在编译时初始化对象的C样式函数指针,以便它调用对象的成员函数吗? [英] Can I initialize an object's C style function pointer at compile time so that it calls the object's member function?

查看:93
本文介绍了我可以在编译时初始化对象的C样式函数指针,以便它调用对象的成员函数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个类来包装需要回调函数指针的库。见下文:

I'm writing a class to wrap around a library that requires callback function pointers. See below:

struct LibraryConfig {
    // Omitting other members...
    void (*callback)(const char *);
};

class MyClass {
private:
    LibraryConfig m_config;

public:
    MyClass(const LibraryConfig &config) {
        // Initialize m_config using config, would like to set callback so that it calls
        // this->myCallback().
    }

    void myCallback(const char *);
};

仅声明MyClass的静态实例,因此可以在编译时保持构造。我已经尝试了使用MyClass指针的lambda和模板函数,但是我要么无法在构造函数中完成此操作,要么无法在编译时实现此功能(通过 this获取实例的地址) & myClass 似乎不可能)。

Only static instances of MyClass will be declared, so construction can be kept within compile-time. I've tried lambdas and template functions that take MyClass pointers, but I either can't accomplish this within the constructor, or can't achieve this at compile-time (getting the address of an instance through this or &myClass at compile-time doesn't seem possible).

将来可能会允许使用 constexpr 参数,这很容易实现,但是现在有没有办法用C ++ 20来实现呢?

constexpr parameters may be allowed in the future, making this trivial to implement, but is there a way to accomplish this right now with C++20?

推荐答案

是的,这显然是可能的。参见以下代码段:

Yes, this is apparently possible. See the below snippet:

struct LibraryConfig {
    void (*callback)(const char *);
};

class MyClass {
private:
    LibraryConfig config;

public:
    consteval MyClass(const LibraryConfig& cfg) :
        config(cfg) {}

    void myCallback(const char *data);
};

int main()
{
    constinit static MyClass mc = {{
        [](const char *data) { mc.myCallback(data); }
    }};
}

在Compiler Explorer上查看工作示例此处。由于 mc 是静态的,因此允许lambda访问而无需捕获。此解决方案可能还有改进的余地,例如

See a working example on Compiler Explorer here. Since mc is static, the lambda is allowed to access it without capture. There may be room for improvement on this solution, e.g. having the lambda be produced by a function.

编辑:

I' ve提出了创建lambda的通用函数:

I've come up with a generalized function to create the lambda:

template<auto& inst, auto func>
consteval auto make_member_callback()
{
    return []<typename... Args>(Args... args) { (inst.*func)(args...); };
}

这样可以实现以下目的(编译器浏览器):

This allows the following to be possible (compiler explorer):

constinit static MyClass mc {{
    make_member_callback<mc, &MyClass::myCallback>()
}};

编辑2:

这是我对此的最后尝试,其中初始化是在类中完成的:

Here is my final try at this, where the initialization is done within the class:

struct LibraryConfig {
    void (*callback)(const char *);
};

template<auto& v, auto f>
constexpr auto member_callback = [](auto... args) { (v.*f)(args...); };

class MyClass {
private:
    LibraryConfig config;

public:
    consteval MyClass(const LibraryConfig& cfg = {}) :
        config(cfg) {}

    template<MyClass& MC>
    constexpr static MyClass& init() {
        MC.config.callback = member_callback<MC, &MyClass::myCallback>;
        return MC;
    }

    void myCallback(const char *data);
};

int main()
{
    constinit static MyClass mc = (mc = MyClass(), MyClass::init<mc>());
}

这篇关于我可以在编译时初始化对象的C样式函数指针,以便它调用对象的成员函数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆