Home > Net >  Trying to return a function from a function with an argument function within it
Trying to return a function from a function with an argument function within it

Time:10-04

I am curious if that's even possible to create a static function in another function and then return that static function with an argument function within it. So far what I've tried doesn't work at all, and when I use raw function pointers the code fails to compile.

#include <iostream>
#include <functional>

//both do not work but this one doesn't even compile
/*
void (*func(void (*foo)()))()
{
    static void (*copy)();
    copy = [&]() { foo(); };
    return copy;
}
*/

std::function<void(void)> Foo(std::function<void(void)> func)
{
    static std::function<void(void)> temp = [&]() { func(); };
    return temp;
}

int main()
{
    Foo([]() { std::cout << 123 << '\n'; });
}

CodePudding user response:

It works, you simply never invoke the function:

#include <iostream>
#include <functional>

std::function<void(void)> Foo(std::function<void(void)> func)
{
    static std::function<void(void)> temp = [&]() { func(); };
    return temp;
}

int main()
{
    // Notice final `()`
    Foo([]() { std::cout << 123 << '\n'; })();
}

But you are capturing the function by reference, so you have to make sure the capturer doesn't outlive it. Otherwise you could copy capture it.

CodePudding user response:

The problem with your commented func is that a lambda which captures anything cannot convert to a pointer to function. Lambda captures provide data saved at initialization to be used when called, and a plain C function does not have any data other than its passed arguments. This capability is actually one of the big reasons std::function is helpful and we don't just use function pointers for what it does. std::function is more powerful than a function pointer.

Of course, func could instead just do copy = foo; or just return foo;, avoiding the lambda issue.

One problem with Foo is that the lambda captures function parameter func by reference, and then is called after Foo has returned and the lifetime of func has ended. A lambda which might be called after the scope of its captures is over should not capture them by reference, and std::function is an easy way to get into that bad situation. The lambda should use [=] or [func] instead.

Note that your static inside Foo is not like the static in front of an actual function declaration. It makes temp a function-static variable, which is initialized only the very first time and then kept. If Foo is called a second time with a different lambda, it will return the same thing it did the first time. If that's not what you want, just drop that static. Linkage of the functions/variables is not an issue here.

(It's a bit strange that Foo puts a std::function inside a lambda inside a std::function which all just directly call the next, instead of just using the original std::function. But I'll assume that's just because it's a simplified or learning-only example. If the lambda did something additional or different, this would be a fine way to do it.)

Your main ignores the function returned from Foo. Maybe you meant to call what Foo returns, with

int main()
{
    Foo([]() { std::cout << 123 << '\n'; })();
}
  • Related