This is cursed: https://github.com/es3n1n/defendnot/blob/master/defendnot-lo... If you're curious what's actually going on there: https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
can someone well versed in explaining CPP magic explain what is going on and why it is cursed?
defer->void { CoUninitialize(); };
Using the macros in the second linked file, this expands to: auto _defer_instance_1234 = Defer{} % [&]()->void { CoUninitialize(); };
* The 1234 is whatever the line number is, which makes the variable name unique.* auto means infer the type of this local variable from the expression after the =.
* Defer{} means default construct a Defer instance. Defer is an empty type, but it allows the % following it to call a specific function because...
* Defer has an overloaded operator%. It's a template function, which takes a callable object (type is the template parameter Callable) and returns a DeferHolder instance.
* [&]()->void { /*code here*/ }; is C++ syntax for a lambda function that captures any variables it uses by address (that's the [&] bit), takes no parameters (that's the () bit) and returns nothing (that's the ->void bit). The code goes in braces.
* DeferHolder calls the function it holds when it is destroyed.
It's subjective but some (including me!) would say it's cursed because it's using a macro to make something that almost looks like C++ syntax but isn't quite. I'm pretty confident with C++ but I had no idea what was going on at first (except, "surely this is using macros somehow ... right?"). [Edit: After some thought, I think the most confusing aspect is that defer->void looks like a method call through an object pointer rather than a trailing return type.]
I'd say it would be better to just be honest about its macroness, and also just do the extra typing of the [&] each time so the syntax of the lambda is all together. (You could then also simplify the implementation.) You end up with something like this:
DEFER([&]()->void { CoUninitialize(); });
Or if you go all in with no args lambda, you could shorten it to: DEFER({ CoUninitialize(); });