我可以在编译时初始化对象的C样式函数指针,以便它调用该对象的成员函数吗?

问题描述 投票:0回答:1

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

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获取实例的地址)在编译时似乎不可能)。

constexpr参数将来可能会被允许使用,因此实现起来并不容易,但是现在有没有办法使用C ++ 20来完成此工作?

c++ c++20
1个回答
0
投票

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

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 here上的工作示例。由于mc是静态的,因此允许lambda访问而无需捕获。此解决方案可能还有改进的余地,例如由函数产生lambda。

编辑:

我想出了一个通用函数来创建lambda:

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

这允许以下操作(compiler explorer):

constinit static MyClass mc {{
    make_member_callback<&mc, &MyClass::myCallback>()
}};
© www.soinside.com 2019 - 2024. All rights reserved.