
Lambdas: From C++11 to C++20, Part 2 - joebaf
https://www.bfilipek.com/2019/03/lambdas-story-part2.html
======
tlb
Related to the capture of this and exceeding its lifetime, I've been doing it
thusly:

    
    
      class Foo : enabled_shared_from_this<Foo> {
    
        void start_callback() {
          auto thisp = shared_from_this();
    
          function_taking_callback([this, thisp](int err) {
            if (err) errFlag = true; 
          });
        }
    
        bool errFlag{false};
      }
    

The idea is that thisp is captured in the lambda and extends the lifetime of
this until the callback is destroyed. And because this is also captured you
can refer to member variables implicitly.

~~~
jdsully
I've used this in the past, but I've had trouble with "phantom callbacks".
Where the logic of the program assumes the object is gone, and it ends up
changing program state unexpectedly. The problem with shared pointers is
ownership is not clear - just because you don't segfault doesn't mean there's
no bug.

~~~
zelos
Exactly. I've had endless arguments about that exact point with shared_ptr.
IMHO, shared_ptr should be used as a last resort, where ownership of something
truly is shared. Use unique_ptr for everything else.

Just using it for convenience for things like callbacks will lead to weird,
hard-to-debug bugs in more complex code.

------
ktpsns
Wow, as somebody who has "seriously" worked with C++ professionally since
~5years and with more "user friendly" languages since decades, these new
features don't blow me out of the socks. Conversely, I'm terrified by the
super complex syntax of these examples. Sure, these are synthetical border
cases, but it shows the abysses of C++ logic. I get headache already with
error messages from contemporary C++ templating and don't even got my hands
touched with error messages from future templated lambdas à la C++...

~~~
shereadsthenews
Some of them are complex, some are less complex than they used to be. For
example look at the first article in this series that discusses the very
common mistake of incorrect parameter types leading to unwanted copies, which
is solved by generic lambdas where the compiler is permitted to deduce the
type.

    
    
      std::map<std::string, int> numbers { 
        { "one", 1 }, {"two", 2 }, { "three", 3 }
      };
    
      // each time entry is copied from pair<const string, int>!
      std::for_each(std::begin(numbers), std::end(numbers), 
        [](const std::pair<std::string, int>& entry) {
            std::cout << entry.first << " = " << entry.second << '\n';
        }
      );
    

This has an error, which is harder to commit in c++14 and forward, with a more
compact expression:

    
    
      std::for_each(std::begin(numbers), std::end(numbers), 
        [](const auto& entry) {
            std::cout << entry.first << " = " << entry.second << '\n';
        }
      );

~~~
mehrdadn
In all honesty in my experience both of these approaches are wrong. Rather,
it's using the good ol' typedef, which you should already be using pretty
liberally anyway:

    
    
      typedef std::map<std::string, int> Numbers;
      Numbers numbers { 
        { "one", 1 }, {"two", 2 }, { "three", 3 }
      };
    
      // each time entry is copied from pair<const string, int>!
      std::for_each(std::begin(numbers), std::end(numbers), 
        [](const Numbers::value_type& entry) {
            std::cout << entry.first << " = " << entry.second << '\n';
        }
      );
    

Or if you're feeling particularly pedantically correct, you can replace const
Numbers::value_type& with Numbers::const_reference, but I don't go that far
generally.

IMHO one of the mistakes of (many, even very experienced) C++ programmers is
that they don't realize typedefs are such a powerful tool to be used liberally
throughout a code base, and they instead overuse auto and decltype. Typedefs
prevent you from repeating yourself, prevent accidents like these, make
changing the underlying types a breeze, are self-documenting, and (when needed
on occasion) let you use a different type for a variable than the expression
used to initialize it, which isn't possible with auto.

------
0db532a0
Part 1 says that it is not correct to call a lambda which value-captures a
member of a temporary instance of a class. Is that really correct? Isn’t the
whole point of value-capturing that the value is copied and preserved
regardless of the life of the source of the captured value?

~~~
Negitivefrags
This is only related to the use of the _this_ pointer.

If you have a member of a class called _s_ then any mention of _s_ inside a
member function of the class is really a mention of _this- >s_.

After you understand that, you can just apply all the regular rules of lambdas
to understand why it gets you in to trouble.

 _this- >s_ is a capture of _this_ , not _s_. _this_ is a pointer and
therefore capturing it by value isn't going to extend the lifetime of the
object it points to.

~~~
0db532a0
I see from the below link that the ‘STAR this’ pointer would be captured
implicitly by reference in this case. This happens regardless of a default
capture type if it does exist.

To truly capture a member by value, you can (1) make a copy of that value in
the enclosing function, thus making it an automatic variable which can be
value-captured, (2) value-capture through an initialiser in the capture list
or (3) you can indicate ‘STAR this’ (since C++17) as a capture, which then
captures the ‘this’ as a value copy and thus transitively your member.

[https://en.cppreference.com/w/cpp/language/lambda#Lambda_cap...](https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture)

------
amelius
Is it possible yet to use C++ productively without the preprocessor at all
(including in the standard libraries)?

If not, then the C++ committee should focus on that, imho.

~~~
arijun
What’s the problem with the preprocessor?

~~~
amelius
Sorry, perhaps I should have elaborated on that. See for example the top
answers here for a good discussion:

[https://stackoverflow.com/questions/14041453/why-are-
preproc...](https://stackoverflow.com/questions/14041453/why-are-preprocessor-
macros-evil-and-what-are-the-alternatives)

------
ufo
The website seems to have been hugged to death. Does anyone have an
alternative link or cache? (I tried to get one from google but it is 404-ing)

~~~
dmix
Its back up now but here’s a cache
[http://archive.is/lP77x](http://archive.is/lP77x)

------
fefe23
Thank you!

This was helpful, concise, well written, yet did not throw a SUBSCRIBE TO OUR
NEWSLETTER popup in my face, did not ask me to create an account, did not
bombard me with ads and did not come across as the usual LOOK AT ME I'M
AWESOME HIRE ME. If I could upvote this more, I would.

------
chris_wot
Isn’t it better to learn lisp first?

