C++ Weekly - Ep 334 - How to Put a Lambda in a Container

Поделиться
HTML-код
  • Опубликовано: 15 сен 2024
  • ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
    Upcoming Workshop: C++ Best Practices, NDC TechTown, Sept 9-10, 2024
    ► ndctechtown.co...
    Upcoming Workshop: Applied constexpr: The Power of Compile-Time Resources, C++ Under The Sea, October 10, 2024
    ► cppunderthesea...
    Ep 332 - C++ Lambda vs std::function vs Function Pointer - • C++ Weekly - Ep 332 - ...
    T-SHIRTS AVAILABLE!
    ► The best C++ T-Shirts anywhere! my-store-d16a2...
    WANT MORE JASON?
    ► My Training Classes: emptycrate.com/...
    ► Follow me on twitter: / lefticus
    SUPPORT THE CHANNEL
    ► Patreon: / lefticus
    ► Github Sponsors: github.com/spo...
    ► Paypal Donation: www.paypal.com...
    GET INVOLVED
    ► Video Idea List: github.com/lef...
    JASON'S BOOKS
    ► C++23 Best Practices
    Leanpub Ebook: leanpub.com/cp...
    ► C++ Best Practices
    Amazon Paperback: amzn.to/3wpAU3Z
    Leanpub Ebook: leanpub.com/cp...
    JASON'S PUZZLE BOOKS
    ► Object Lifetime Puzzlers Book 1
    Amazon Paperback: amzn.to/3g6Ervj
    Leanpub Ebook: leanpub.com/ob...
    ► Object Lifetime Puzzlers Book 2
    Amazon Paperback: amzn.to/3whdUDU
    Leanpub Ebook: leanpub.com/ob...
    ► Object Lifetime Puzzlers Book 3
    Leanpub Ebook: leanpub.com/ob...
    ► Copy and Reference Puzzlers Book 1
    Amazon Paperback: amzn.to/3g7ZVb9
    Leanpub Ebook: leanpub.com/co...
    ► Copy and Reference Puzzlers Book 2
    Amazon Paperback: amzn.to/3X1LOIx
    Leanpub Ebook: leanpub.com/co...
    ► Copy and Reference Puzzlers Book 3
    Leanpub Ebook: leanpub.com/co...
    ► OpCode Puzzlers Book 1
    Amazon Paperback: amzn.to/3KCNJg6
    Leanpub Ebook: leanpub.com/op...
    RECOMMENDED BOOKS
    ► Bjarne Stroustrup's A Tour of C++ (now with C++20/23!): amzn.to/3X4Wypr
    AWESOME PROJECTS
    ► The C++ Starter Project - Gets you started with Best Practices Quickly - github.com/cpp...
    ► C++ Best Practices Forkable Coding Standards - github.com/cpp...
    O'Reilly VIDEOS
    ► Inheritance and Polymorphism in C++ - www.oreilly.co...
    ► Learning C++ Best Practices - www.oreilly.co...

Комментарии • 58

  • @flamendless
    @flamendless 2 года назад +31

    Devops be like "i know to to put aws lambda in docker container"

  • @johnytoxic
    @johnytoxic 2 года назад +16

    I suggest we introduce "named lambdas" for the next C++ version. That way, developers will be able to name their lambdas, a.k.a. giving them an actual type. By doing so, we complete the loop to structs again.
    Totally not a joke.

    • @hanyanglee9018
      @hanyanglee9018 2 года назад +1

      Even the fastest we do this, it's c++29. If Carbon language is good enough, do we need a c++29?

    • @wonigu
      @wonigu 2 года назад

      sure ) they call it functor or function object

    • @X_Baron
      @X_Baron 2 года назад

      Local structs can't capture local variables, I believe, so there's something there.

    • @wonigu
      @wonigu 2 года назад

      @@X_Baron hold my beer )
      main()
      {
      int i = 42;
      struct {
      int operator()(int i) {
      return i + _i;
      }
      int _i;
      } my_local{ i };
      i = my_local(-42);
      }

    • @hanyanglee9018
      @hanyanglee9018 2 года назад

      @@X_Baron hold my beer too.

  • @maartenofbelgium
    @maartenofbelgium 2 года назад +28

    Would an episode about the current state of c++20 modules be interesting?
    CMake does not yet have support and gcc 12's support is very incomplete.

    • @cppweekly
      @cppweekly  2 года назад +5

      Because the tooling support is so non-existent, and even watching videos from experts on modules... I just don't see how I can yet fit it into the format of this channel.
      I think after we get modules in CMake I'd be able to show something.

    • @maartenofbelgium
      @maartenofbelgium 2 года назад +1

      @@cppweekly Totally agree. The "howto" is completely different for every compiler. For gcc 12.1, you need to compile every system header for which you need CMake or similar. Build2 supports modules, but that system has no market share.

    • @superscatboy
      @superscatboy 2 года назад +2

      It's a little disappointing how slowly the tools are catching up. Modules are such a huge win for the language - I want them literally everywhere, and I want it yesterday.

  • @jamescoulter9659
    @jamescoulter9659 2 года назад +2

    Videos like this are a helpful reference that save time when I need to compare alternatives. 👍

  • @xarcaz
    @xarcaz 2 года назад +2

    IMHO, the by far cleanest solution is to use a vector of function pointers *but* if you want some context (akin to a capture list) just wrap it in a struct and have it as a function parameter.

    • @jespa003
      @jespa003 2 года назад +1

      Pointers always wins, but C++ is afraid of pointers 😛

  • @Cons-Cat
    @Cons-Cat 2 года назад +1

    template
    struct PatternCallback {
    Function callback;
    };
    I can put a lambda in the aggregate constructor here, in C++20. This is abridged real code that I actually use.

  • @DBZM1k3
    @DBZM1k3 2 года назад +1

    I think it would be possible to implement something like what Sean Parent did with Runtime Polymorphism and have a struct or class wrapper to store lambdas. That way you could have an array of different lambdas. I wonder how performant it would be in comparison to std::function.

  • @majohime
    @majohime 2 года назад +1

    Bookmark clang (trunk) and gcc (trunk) with star button.

  • @dennisrkb
    @dennisrkb 2 года назад +1

    If you want to store multiple lambdas directly, you can use a tuple, but the size will be fixed =S

  • @TheMR-777
    @TheMR-777 2 года назад

    TBH, New addition to C++23 has truly surprised me!
    Specially the arrival of std::print

  • @__hannibaalbarca__
    @__hannibaalbarca__ Год назад

    I understand your love ❤️ to Lambda
    Same me to Gamma and tZita functions.

  • @willofirony
    @willofirony 2 года назад +1

    Given that lambdas are syntactic sugar for creating functors (albeit a very useful lump of sugar), one wonders whether the assembler code generated by placing them into containers would be more efficient than (we are still at the assembler level) accessing a table of address of conventional functions by index. Now, the effort for the programmer to create said table, not to mention defining all those functions is something of a first world problem. Still it would be interesting to see a comparison of the code generated by the two approaches.

    • @wonigu
      @wonigu 2 года назад

      it's an interesting difference here that functor is an object itself but not just a plain conventional function, so you able to put in container and some part of data as well, among function pointer to operator()
      but here comes the std::function as an universal container-wrapper for any callable object.

  • @oschonrock
    @oschonrock 2 года назад +4

    OK, Nice. But that is not the same functionality as std::function.
    Yes we can cope with captures that way, but we cannot have lambdas with different code in the body....
    Basically I struggle to see that how std::function is not the practical solution here (unless the function pointer optimisation is worthwhile for you in the captureless case).
    I suspect that mostly we would want the type erasure.. different captures and different code in the body?

    • @anon_y_mousse
      @anon_y_mousse 2 года назад

      I suppose an argument could be made that since C++ lets you, you could implement it in the C style, and thus it would be relatively easy to handle, just with a lot less auto generated hidden code. Though I'm sure you'd rather the standards committee just add it to C++ since that would be easier and truthfully there's not much reason not to.

    • @cppweekly
      @cppweekly  2 года назад +2

      std::function *is* the practical use case here, this is just showing various possibilities.

  • @chrisminnoy3637
    @chrisminnoy3637 Год назад

    A feature I would like to see is that you can have lambdas inherit FROM a class, so you could create nameless scoped class types that implement something from an abstract base class. Inspired by the unnamed classed in Java.

    • @cppweekly
      @cppweekly  Год назад

      Ok, this is a very interesting idea. I'm going to have to play with it and see what I can figure out. I think there are some possibilities.

  • @fcolecumberri
    @fcolecumberri 2 года назад

    I wonder if the amount of code vector would have generated if emplace_back() would have been used instead of push_back(), maybe the same since the compiler might optimize that out, but emplace_back() would have been better.
    Also I wonder how many cases do you need to dynamically load lamdas inside a container (I have only done that once in my life), I mean, if you know at compiletime what are you going to use, you could use an array which might be able to be generated at constexpr time.

    • @ALivingDinosaur
      @ALivingDinosaur 2 года назад +3

      > how many cases do you need to dynamically load lamdas inside a container
      Two somewhat obvious cases are signal-slot system and worker thread's job/task queue.

  • @ohwow2074
    @ohwow2074 2 года назад +1

    Amazing as always. I would also like to see an episode on ranges library.

    • @cppweekly
      @cppweekly  2 года назад

      I'm tracking that idea here: github.com/lefticus/cpp_weekly/issues/87 add any notes if you'd like to

  • @sarnikowskirafal
    @sarnikowskirafal 2 года назад

    what if I wanted to put different lambdas in one container, struct my_lambda wouldn't work, I'd need interface and virtual table for that?

    • @cppweekly
      @cppweekly  2 года назад

      At which point you are much better off using `std::function`, which was designed for that exact purpose.

  • @stephenhowe4107
    @stephenhowe4107 2 года назад

    Jason: have you covered when std::ref() and std::cref() are necessary? Thanks

    • @cppweekly
      @cppweekly  2 года назад

      That's a great idea! Please go to the list of episode ideas and add it there so I can keep track of it - github.com/lefticus/cpp_weekly/issues/

  • @hanyanglee9018
    @hanyanglee9018 2 года назад

    Great video. But no matter how, the capture is not available in this case.

    • @cppweekly
      @cppweekly  2 года назад

      it does work in the decltype(lambda) case, yes. The capture is available then.

  • @PedroOliveira-sl6nw
    @PedroOliveira-sl6nw 2 года назад

    I used to work in a project that used a lot of these techniques. I thought about asking you for code reviews at some point.

    • @ChiliTomatoNoodle
      @ChiliTomatoNoodle 2 года назад

      Fancy meeting you here :]

    • @cppweekly
      @cppweekly  2 года назад +1

      Sometimes just using std::function is the best idea.

  • @michaelgilch3645
    @michaelgilch3645 2 года назад +1

    Why not mention heterogeneous containers? This should work like charm with tuple, although the handling is much more complicated.

    • @wonigu
      @wonigu 2 года назад

      heterogeneous container for callable objects? The problem here is that you have to know how to call it like foo(42); but not foo(42, "universe");

    • @cppweekly
      @cppweekly  2 года назад

      The problem is that it would be an infinite set of possible things to be contained once you take into account lambdas with captures.

  • @quentinquadrat9389
    @quentinquadrat9389 Год назад

    Could be nice to explain how to store method pointers of derived classes. Something like base class: class Button { template void setCallback(F) {m_m_callback = fun; } ; void onClick() { m_callback(); } std::function m_callback; }; Derived class: class MyButton: public Button { MyButton() { setCallback([this](){ this->myCallback(); } ); } void myCallback() {..} }

  • @treyquattro
    @treyquattro 2 года назад +3

    rolling your own kind of obviates lambdas. It would be better if the language handled this (in a future version perhaps). Also, I've been relegated firmly to the "average programmer camp", thanks!

    • @masheroz
      @masheroz 2 года назад

      C++31, to be implemented by 2037.

  • @victotronics
    @victotronics 2 года назад +2

    "All that code that is generated". Sure, but that's only for pushing onto that vector, which you do once. In my book the only thing that counts is how efficient is calling the lambda, because that's what I'll be doing millions of times. But: clever trick. In my mental book it goes.

    • @Possseidon
      @Possseidon 2 года назад +3

      Calling it will also have an additional indirection.

    • @cppweekly
      @cppweekly  2 года назад +1

      I still should have done a measurement.

    • @victotronics
      @victotronics 2 года назад

      @@Possseidon But that's instruction handling. The instruction cache is separate from the data cache. I'm usually much more worried about the data cache. An instruction extra here and there is completely negligible compared to the cost of moving data. It would be interesting to code an exmple and see if that indirection is actually measurable.

  • @nicolabombace2004
    @nicolabombace2004 2 года назад

    I really like the implementation with your own type my_lambda.. This could be even be implemented with a virtual () operator to allow different functions.

    • @LEpigeon888
      @LEpigeon888 2 года назад +1

      It would hardly be better than a std::function then.

    • @nicolabombace2004
      @nicolabombace2004 2 года назад

      A functor object can have a state, sometimes this feature is preferable to std::function.

  • @axelBr1
    @axelBr1 2 года назад +2

    I really don't understand the fascination with lambdas. To me lambdas and functional programming in general seem a lot like my experience with coding as part of my engineering course; we had a whole year of learning coding using Pascal because that is what the Computing Science Dept. said was a "good" language. The at the very end of the year we had a quick course on FORTRAN because that is what industry actually uses. Ultimately I spent many years implementing bits and pieces in FORTRAN and did personally use Pascal (as it was the only language I could get my hands on in 1992), for a few weeks. After many years away from C++ I was introduced to some code in Haskell at the local Uni. and thought it looked complete garbage and no one is going to be writing 10,000s lines of code in that and then maintaining it 10 years later, (like I've tried to do with some of my C++).
    So I don't understand all this fuss about putting a lambda into a container, when you can just create a class or a Struct and place it into the container.

    • @anon_y_mousse
      @anon_y_mousse 2 года назад

      I think it's just that people want the syntactic sugar. There's really no hardware limitation to providing it either, it's just that the language does not. You could argue for or against either method until you're blue in the face, but ultimately I figure it's just down to preference. I could implement in C what C++ provides, and have done an extensive amount of that, but everything is manual. Arguably, with the syntactic sugar, you don't need to type as much and thus are less prone to errors, but that's what the compiler and tab complete are for to me. As in 12[tab] and I've got it.

    • @treyquattro
      @treyquattro 2 года назад +1

      lambdas are a perfect use for this kind of scenario where you want a piece of code but it doesn't need to be named: data-driven collections of graphics code are a good example. So I understand why Jason would come up with this kind of example. The problem is the strong typing by the compiler that's hidden from the user. Lambdas should probably be revisited by the committee to make them more general-purpose, more _generic_ in fact, so that examples like the one in the video don't require so much thought and engineering to get around, and still produce extremely performant executables, which is C++'s claim to fame.
      Pascal, eh? The best thing that probably ever came out of Pascal was Anders Hejlsberg!