r-lyeh / tinybits

Tiny bits and useful snippets that I keep using everywhere (C, C++)
The Unlicense
314 stars 23 forks source link

tinydefer: converting capturing lambda to a function pointer #4

Closed DanielChabrowski closed 5 years ago

DanielChabrowski commented 5 years ago

Hello, I just stumbled upon this repo and took a look. Tinydefer, while quite interesting as a concept, just doesn't work as a capturing lambda cannot be converted to a function pointer.

<source>:17:5: error: assigning to 'void (*)()' from incompatible type '(lambda at <source>:17:5)'
    defer {
    ^~~~~~~

<source>:10:70: note: expanded from macro 'defer'
#define defer        defer DEFER_UNIQUE_NAME; DEFER_UNIQUE_NAME.fn = [&]

To fix this it is possible to change the type of fn to std::function.

struct defer {
    std::function<void()> fn;
    ~defer() { fn(); }
};

However, this can cause a dynamic memory allocation pretty easily.

I was wondering how did you make it work with a function pointer?

r-lyeh commented 5 years ago

Ah, good catch. VS2013 compiles the sample without problems, but VS2015 and VS2017 wont. I guess VS2013 compiler was "smart" enough as to downgrade the lambda scope to [] since I was only using (public) puts symbols inside the lambdas. I am changing to std::function<> as you just proposed since it makes the best usage compromise to me, even if that dynalloc is triggered. Solutions for that? Maybe use a different std::function<> implementation that triggers compiler's Small Function Optimization :P

r-lyeh commented 5 years ago

Btw, I'd go with a stack based allocator, but... have you tried any of these? https://blog.demofox.org/2015/02/25/avoiding-the-performance-hazzards-of-stdfunction/

DanielChabrowski commented 5 years ago

@r-lyeh I have tried neither. I did however make it work for c++17, all thanks to CTAD. https://godbolt.org/z/YjySp5

r-lyeh commented 5 years ago

cool trick!

BlankSpruce commented 5 years ago

Expanding on @DanielChabrowski's idea and a little bit of operator overloading it can be achieved in C++11 as well: https://godbolt.org/z/TyaGtm