类型转换回调函数
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”以了解上述语法。
我可以对回调函数进行类型转换吗?
我喜欢写一个注册和调用某些回调函数的库。
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”以了解上述语法。