10

I'm starting to develop applications using C++11 lambdas, and need to convert some types to function pointers. This works perfectly in GCC 4.6.0:

void (* test)() = []()
{
    puts("Test!");
};

test();

My problem is when I need to use function or method local variables within the lambda:

const char * text = "test!";

void (* test)() = [&]()
{
    puts(text);
};

test();

G++ 4.6.0 gives the cast error code:

main.cpp: In function 'void init(int)':
main.cpp:10:2: error: cannot convert 'main(int argc, char ** argv)::<lambda()>' to 'void (*)()' in initialization

If use auto, it works ok:

const char * text = "Test!";

auto test = [&]()
{
    puts(text);
};

test();

My question is: how can I create a type for a lambda with [&]? In my case, I can not use the STL std::function (because my program does not use C++ RTTI and EXCEPTIONS runtime), and It has a simple implementation of function to solve this problem?

Omer Mor
  • 5,216
  • 2
  • 34
  • 39
Raphael Basso
  • 137
  • 1
  • 1
  • 6
  • 8
    Sounds like an instance of the [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – R. Martinho Fernandes Jun 12 '12 at 13:32
  • 3
    You cannot convert a capturing lambda to a function pointer. Explain what you're trying to do. – Etienne de Martel Jun 12 '12 at 13:35
  • You have explained (badly) an attempted solution, whilst not describing what you actual problem is. Please tell us what you actual problem is – thecoshman Jun 12 '12 at 13:38
  • @Antonio: I've made some corrections to my answer after looking at an implementation of `std::function`. You should probably take a look. – Nicol Bolas Jun 12 '12 at 14:51
  • Does this answer your question? [Passing capturing lambda as function pointer](https://stackoverflow.com/questions/28746744/passing-capturing-lambda-as-function-pointer) – user7610 Oct 21 '20 at 13:03

4 Answers4

10

I can not use the STL std::function (because my program does not use C++ RTTI and EXCEPTIONS runtime)

Then you may need to write your own equivalent to std::function.

The usual implementation of type erasure for std::function doesn't need RTTI for most of its functionality; it works through regular virtual function calls. So writing your own version is doable.

Indeed, the only things in std::function that need RTTI are the target_type and target functions, which are not the most useful functions in the world. You might be able to just use std::function without calling these functions, assuming that the implementation you're using doesn't need RTTI for its usual business.

Typically, when you disable exception handling, the program simply shuts down and errors out when encountering a throw statement. And since most of the exceptions that a std::function would emit aren't the kind of thing you would be able to recover from (calling an empty function, running out of memory, etc), you can probably just use std::function as is.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
9

Only lambdas with no capture can be converted to a function pointer. This is an extension of lambdas for only this particular case [*]. In general, lambdas are function objects, and you cannot convert a function object to a function.

The alternative for lambdas that have state (capture) is to use std::function rather than a plain function pointer.


[*]: If the lambda that holds state could be converted to function pointer, where would the state be maintained? (Note that there might be multiple instances of this particular lambda, each one with it's own state that needs to be maintained separately)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Well, if you pass it by value like this `const int c; [c](int i)->int{return i*c;}` it would make a lot of sense... – Barney Szabolcs Dec 05 '12 at 05:13
  • @BarnabasSzabolcs: It depends, consider `std::function f(int x) { const int c = x; return [c](int i){return i*c;} };`. The functor returned by `f` depends on it's argument and thus has state. Only if the capture was a constant expression it could be factored into a plain function. – David Rodríguez - dribeas Dec 05 '12 at 14:32
  • Hm. I agree, partly. It still can be pulled off, but the solution can be expensive, as the program would need to copy the code of the lambda function every time with changing the value of c in the function code. (or if not copying the entire code of the function, it needs to make planned jumps, where the jumps can slow things down.) – Barney Szabolcs Dec 05 '12 at 18:20
  • @BarnabasSzabolcs: I don't think this can even be done, consider that the argument to the function can be a runtime value (read from user input for example) and you cannot create functions based on runtime values. You could imagine storing the value aside, but to ensure that the different lambdas not get their values clobbered when a new lambda is created, which in turn would require dynamic memory whose use would be intractable for the compiler... – David Rodríguez - dribeas Dec 05 '12 at 19:15
  • Tried on both VS2013 and xcode6. Lambda without capture can be converted to function pointer, thanks for point out. – r0n9 Jun 22 '15 at 08:32
  • msdn lambda page uses an example with lambda as an arg https://msdn.microsoft.com/en-us/library/dd293608.aspx – Abhinav Aug 30 '15 at 11:55
6

As has been mentioned, only lambdas that capture nothing can be converted to function pointers.

If you don't want to use or write something like std::function then another alternative is to pass as parameters the things you would otherwise capture. You can even create a struct to hold them.

#include <iostream>

struct captures { int x; };
int (*func)(captures *c) = [](captures *c){ return c->x; };

int main() {
    captures c = {10};

    std::cout << func(&c) << '\n';
}

Another alternative is to use global/static/thread_local/constexpr variables which do not require capturing.

bames53
  • 86,085
  • 15
  • 179
  • 244
2

You can use std::function, it doesn't need any "runtime". Otherwise, look here for a sketch how to implement std::function yourself.

Community
  • 1
  • 1
jpalecek
  • 47,058
  • 7
  • 102
  • 144