I'm seeking help in validating the correctness of the following code:
#include <iostream>
// Implementing a kind of 'reference' to any functor with a void(void) call signature
struct FunctionView {
template<class F>
static void function_caller_prototype(void *functor)
{
auto f = reinterpret_cast<F *>(functor);
(*f)();
}
void (*function_caller) (void *);
void *functor;
template<class F> FunctionView(F *f):
function_caller{function_caller_prototype<F>},
functor{const_cast<void *>(reinterpret_cast<const void*>(f))} {}
void operator() () const
{
function_caller(functor);
}
};
void foo()
{
std::cout << "Calling foo" << std::endl;
}
int main(int argc, const char *argv[])
{
auto lambda = [&argc]() {
std::cout << "Calling lambda with argc " << argc << std::endl;
};
FunctionView cb_foo(foo);
FunctionView cb_lambda(&lambda);
cb_foo();
cb_lambda();
return 0;
}
As far as I can tell, the reinterpret_cast should not pose any problem, because the stored functor object is reinterpreted back to it's original type when being used inside the function_caller_prototype function template. void* has no alignment requirements and there is no data being allocated, copied or moved. I'm also casting away the constness of the original functor but that is also restored in function_caller_prototype. Despite the FunctionView::operator() is a const member function, the functor's operator() might not be const and do modifications on itself but that should not be a problem.
Am I missing something or is this code totally OK as I suspect?
Building it with different compilers and running tests with address sanitizer. No issues were detected.