Search code examples
c++functionc++11lambda

function::target(): How does the template type work for lambdas?


I want to store a lambda expression in a function object, then retrieve its underlying function pointer. For reasons I do not understand, function::target() is a templated function that returns nullptr if the incorrect type is passed in (I'm working in C++11).

  1. What type should I use in the template to correctly retrieve the underlying lambda pointer?
  2. Why does function::target() require a template if function is already templated?
  3. If the type of a lambda function is different from that of a global function, then why can both be stored into the same function object?

I have a vague understanding of how lambdas are expressions that result in temporary functions that are bound to namespaces and thus have a different type depending on which namespace they reside in. I have no idea if that impression is correct or how to apply it to what I use in the template argument. Any insight into what C++ magic is going on here would be greatly appreciated.

Relevant Links

Code Example

void foo(int) { std::cout << "foo" << std::endl; }

int main() {
    std::function<void(int)> a(foo); // well-defined global function
    std::function<void(int)> b([](int) -> void {}); // temporary lambda expression

    auto bar = [](int) -> void {}; // lambda expression stored in variable
    std::function<void(int)> c(bar);

    std::cout << a.target<void(*)(int)>() << std::endl; // 0x7ffe8e74ecf0
    std::cout << b.target<void(*)(int)>() << std::endl; // 0
    std::cout << c.target<void(*)(int)>() << std::endl; // 0
    std::cout << &bar << std::endl;                     // 0x7ffe8e74ecef

    return 0;
}

Solution

  • The result of a lambda expression is an object, not a function.
    Every lambda expression has a unique but unnamed type.

    You can recover an object from c since bar has a name; c.target<decltype(bar)>() returns a pointer to an object of that type (note that it's not a function pointer).

    You can't recover the object in b since you can't describe its type.