About Blog Contact

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;

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.