Type Deduction for Lambda Expressions
Due to the design constraints of a library, I need to pass a pointer to a lambda expression as a void *
, like this:
auto f = [](double x) -> double { return x + 1; };
auto func_to_ptr = [](double x, void *otherstuff) -> double {
auto func = reinterpret_cast<std::function<double(double)>*>(otherstuff);
return func->operator()(x);
};
However, when calling func_to_ptr
:
func_to_ptr(1.0, (void*)&f);
the program would segfault at runtime. Why?
Contrary to common expectation, a lambda expression is not of the std::function
type. According to standards, is:
The lambda expression is a prvalue expression of unique unnamed non-union non-aggregate class type, known as closure type.
We can see this by checking its mangled name:
#include <typeinfo>
#include <cxxabi.h>
int status;
char* realname;
const std::type_info & ti = typeid(f);
realname = abi::__cxa_demangle(ti.name(), 0, 0, &status);
std::cout << status << std::endl;
std::cout << realname << " : " << ti.name() << std::endl;
free(realname);
Running it outputs a status code of -2, which means “mangled_name is not a valid name under the C++ ABI mangling rules”, consistent with its type being a special unnamed type.
So now we know the problem: reinterpret_cast
expects a std::function
, while it gets a unnamed closure type. No wonder the reinterpreted pointer does not work. The solution is straight forward: instead of letting the compiler deduct the type, we explicitly ask it to store the lambda expression inside a std::function
:
std::function<double(double)> f = [](double x) -> double { return x + 1; };
The constructor of std::function
takes in any callable type, including unnamed closure types, so now f
is a std::function
object constructed according to the lambda expression. Everything works fine after this change.