When I ran the code below I got a "bad_function_call" thrown
void fn(void* f) {
auto fu = static_cast<std::function<void()>*>(f);
(*fu)();
}
int main() {
auto f1 = [] () {
std::cout << "f1";
};
fn(&f1);
}
Of course code would work if I wrote:
void fn(void(*f)()) {
f();
}
int main() {
auto f1 = [] () {
std::cout << "f1";
};
fn(f1);
}
but it fails when passing &f1 as a void* and converting it to std::function<void()>*.
What's the correct way if I want to do this?
The second version of your code is ok because a lambda without capture can be converted to a function pointer. This conversion is from the type of the lambda to the type of the function pointer.
Once you converted the lambda to a void* you left the type system. There is no proper conversion from void* to a function pointer. To do this you would first need to cast the void* back to the type of the lambda, and then this can again be converted to a function pointer.
Your faulty code is similar to this:
int x = 42;
void* p = &x;
float y = *static_cast<float*>(p);
Expecting the last line to make a proper conversion from int to float is wrong. The void* carries no information on what the actual type of the object is. static_cast<float*>(p) pretends that p would point to a float but it does not.
In modern C++ there is no reason to use void* for type erasure anymore. Only when interfacing legacy code that expects a void* you may need to resort to such unsafe casts. For other cases of type erasure, there is std::any, std::variant, std::function, and more.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With