我正在编写一个类来包装需要回调函数指针的库。见下文:
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来完成此工作?
是的,这显然是可能的。请参见以下代码段:
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>()
}};