类型转换回调函数

Typecast callback functions

我可以对回调函数进行类型转换吗?

我喜欢写一个注册和调用某些回调函数的库。

int MyCaller::add_callback_function(int (*callback_function)(), byte behaviour) {
    this->callback = callback_function;
}

void MyCaller::run() {
    int result = this->callback();
}

// ....

int get_number() { return 42; }
MyCaller my_caller;
my_caller.add_callback_function(get_number, 0);
my_caller.run();

不过,我也想支持callback_functions输出一个布尔值。

bool get_bool() { return true; }
MyCaller my_caller;
my_caller.add_callback_function(get_number, 0);
my_caller.run();

如果我尝试这样做,我的代码似乎 运行 没问题,但 gcc 会给出 warning: invalid conversion from 'bool (*)()' to 'int (*)()' [-fpermissive].

为了避免这个警告,我用一个稍微不同的签名重载了我的 add_callback_function

void MyCaller::add_callback_function(bool (*callback_function)(), byte behaviour) {
    // ...
}

然而,从这一点开始我迷路了。我希望我可以将任何布尔值转换为整数,并调用原始方法:

void MyCaller::add_callback_function(bool (*callback_function)(), byte behaviour) {
    this->add_callback_function(static_cast<int (*)()>(callback_function), byte behaviour);
}

然而,这给出了 error: invalid static_cast from type 'bool (*)()' to type 'int (*)()'

所以我好像做错了什么。

有干净的方法吗?

奖励积分:我的代码存储了一组回调函数,我希望能够有选择地添加上下文参数(例如,允许调用函数以外的方法)。我计划将所有这些回调(具有不同的签名)存储为 int (*)(),并在调用它们之前将它们转换为正确的形式。这是最好的方法吗,还是有其他(也许更好)的方法来处理这个问题?

我能想到的替代方案是只支持一个非常具体的回调签名,但这会迫使用户编写包装器。我喜欢把这个负担放在图书馆。

您可以将一种函数指针类型转换为另一种,但是您只能在将其转换为真实函数指针时调用它类型。您只能将它们存储为错误的签名。

以任何其他方式调用它们会导致未定义的行为。最可能的症状将取决于您的平台当前的调用约定。但真的,只是不要这样做。

最简单正确的解决方案是存储一个

std::function<int()>

这不是函数指针,但可以存储任何回调(包括函数指针),可以使用零参数和 returns 与 [=12= 兼容的内容进行复制、移动和调用](bool 符合条件)。

std::function也可以存储有状态的对象。例如:

struct Foo {
  int count = 0;
  int callback(){ return ++count; }
};

Foo foo;
std::function<int()> f = [&foo]{ return foo.callback(); };

你自然而然地要对一生负责。查找“C++ lambdas”以了解上述语法。