C++ Weekly - Ep 441 - What is Multiple Dispatch (and how does it apply to C++?)

Поділитися
Вставка
  • Опубліковано 2 жов 2024
  • ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
    Upcoming Workshop: Applied constexpr: The Power of Compile-Time Resources, C++ Under The Sea, October 10, 2024
    ► cppunderthesea...
    Is your team under pressure to deliver high-quality software faster? Is lowering costs and increasing speed to market a priority?
    With the right static analysis tools, you can ensure the quality, security, and compliance of your code - without slowing down development. You'll get accurate diagnostics, ensure your code complies with the latest industry standards, and find bugs earlier in the development cycle.
    See which tools are right for you - click the link below to request a free static code analyzer trial!
    ter.li/w9qtls
    Episode details: github.com/lef...
    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
    Amazon Paperback: amzn.to/47MEAhj
    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...

КОМЕНТАРІ • 43

  • @WilhelmDrake
    @WilhelmDrake Місяць тому +10

    Scott Meyers also covered the topic in his book "More Effective C++". Item 31: Making functions virtual with respect to more than one object.
    It was very interesting to get a modern take on the subject. Thank-you!

  • @anon_y_mousse
    @anon_y_mousse Місяць тому +6

    The way I've always dealt with these types of things, not that it comes up terribly often, is to use a bit pattern type ID for the various objects that need to be matched up, and to bitwise-or them together to switch on their meshed type ID's. This is actually one of those test cases where I know that people haven't read the AMD optimization manual. It has this technique in it to deal with condensing and optimizing giant if/else if/else chains in loops, amongst other uses.
    If anyone reads this, I'm going to recommend that you read both the Intel and AMD optimization manuals, because they don't merely give tips for writing better assembly, but also for implementing better and more optimized code patterns in all languages. If you can do it without thinking, then you've properly absorbed the lessons within.

  • @andrewduncan1217
    @andrewduncan1217 Місяць тому +4

    A very interesting modern implementation of double-dispatch. Thanks.

  • @DamianReloaded
    @DamianReloaded Місяць тому +5

    I've found that using overloaded constructors instead of functions makes the compiler generate less code.
    struct collide
    {
    collide(Craft &A, Craft &B) { A.x += B.y; }
    collide(Asteroid &A, Asteroid &B){ A.x += B.y; }
    collide(Craft &A, Asteroid &B){ A.x += B.y; }
    collide(Asteroid &A, Craft &B){ A.x += B.y; }
    };

    • @shipweck6253
      @shipweck6253 Місяць тому +1

      wow this looks very clean

    • @ivanzhechev4215
      @ivanzhechev4215 Місяць тому +3

      It generates 'less' code because the free functions must have an address. If you put them in an anonymous namespace it's the same code.

    • @DamianReloaded
      @DamianReloaded Місяць тому +2

      What about:
      template
      struct collide {
      constexpr collide(const T1 &A, const T2 &B) : m_a(A), m_b(B) { }
      constexpr operator int() const noexcept {
      return result_value;
      }
      int result_value = 0;
      const T1& m_a;
      const T2& m_b;
      };
      Or (edit: it's actually a bit larger)
      template
      struct collide {
      using vtype = std::variant;
      collide (const Craft &, const Craft &) noexcept {std::puts("C/C"); }
      collide (const Asteroid &, const Asteroid &) noexcept { std::puts("A/A");}
      collide (const Craft &, const Asteroid &) noexcept { std::puts("C/A");}
      collide (const Asteroid &, const Craft &) noexcept { std::puts("A/C");}
      collide(const vtype& v1,const vtype& v2) noexcept {
      std::visit(
      [this](const auto &lhs, const auto &rhs) {
      if (lhs.x == rhs.x && lhs.y == rhs.y) {
      collide(lhs, rhs);
      }
      }
      , v1, v2);
      }
      };
      std::vector get_objects()
      {
      return { {Craft(), Asteroid()} };
      }
      void process_collisions(const std::variant &obj) {

      for (const auto &other : get_objects()) {
      collide(obj, other);
      }
      }
      int main ()
      {
      for (const auto &obj : get_objects())
      process_collisions(obj);
      return 0;
      }

  • @taw3e8
    @taw3e8 Місяць тому +4

    Cool trick ^^

  • @pw1169
    @pw1169 Місяць тому +1

    Very interesting! I hope i never see this in production code :D

  • @broken_beyond_belief
    @broken_beyond_belief Місяць тому +4

    not even a cpp dev but still watching Jason Turner. Keep this up man ❤❤

  • @oschonrock
    @oschonrock Місяць тому +4

    very nice.. although If I needed this in such an example, I would seriously question if I have the right design?

    • @fernandoiglesiasg
      @fernandoiglesiasg Місяць тому +1

      In that case, what design would you suggest for the example?

    • @oschonrock
      @oschonrock Місяць тому

      @@fernandoiglesiasg It depends on the wider context. Perhaps make `collide` take a position{int x, int y} object produced from each space object. That makes it single dispatch on the objects and a single version of `collide`?

    • @cppweekly
      @cppweekly  Місяць тому +2

      To me it's just an argument that we want pattern matching so we get this naturally when we need/want it.

    • @fernandoiglesiasg
      @fernandoiglesiasg 20 днів тому

      Aha! That’s interesting, I think I hadn’t considered pattern matching in the context of multiple dispatching. I normally look into Julia doc when want to recall let’s say “multiple dispatching done right”.

  • @grincha09
    @grincha09 Місяць тому +1

    Nice

  • @Voy2378
    @Voy2378 Місяць тому

    would be nice to see if boost::variant2 generates better code than std::variant

  • @ohwow2074
    @ohwow2074 Місяць тому +11

    So this works when we don't have too many derived types and all are known at compile-time. It's cool. And I think it does not fully replace the first solution you had which was using dynamic polymorphism.

  • @jakubskopal43
    @jakubskopal43 Місяць тому +5

    The problem with trailing return types is that if you forget to write the trailing end ( -> CopyableMovableClass&) on a method returning a reference, you will end up copying (because you will have "auto getRefObject()" instead of "auto getRefObject() -> CopyableMovableClass&". If the object has copy constructor all will be compiled without a warning. Too bad that there is not a some kind of warning that user did not write trailing type at least on clang-tidy side.

    • @keris3920
      @keris3920 Місяць тому +4

      I'm confused about your concern. If I forget an & on the legacy syntax, it will create a copy. Also, auto& my_func() is valid syntax, which I would argue is exactly as error prone in this respect as the legacy format

    • @jakubskopal43
      @jakubskopal43 Місяць тому +1

      @@keris3920 It is not the same, the one you talking about is one problem which can be done even with trailing part. you can also write -> auto instead of a -> auto& but on top of that you can also miss out the trailing part without any warning. I see there two possibilities how to make unintented code instead of one.

    • @keris3920
      @keris3920 Місяць тому

      @@jakubskopal43 your entire argument rests on the presumption that copies are a bad thing. Copies can often be faster and don't suffer from some of the lifetime issues that references suffer from (e.g. dangling references). Anyway, that's beside the point.
      The point I'm trying to make, is that regardless of the syntax you use, programmers will always make silly mistakes. I ultimately agree with you that a linter/formatter would help uncover some small bugs in this area. But I could probably list a seemingly infinite amount of bugs that could arise from forgetting parts of a function declaration. At the end of the day, I appreciate your warning, but I don't see trailing return type syntax as the root cause for this flavor of bug.

    • @jakubskopal43
      @jakubskopal43 Місяць тому +1

      ​@@keris3920 I did not say that copies are bad thing. I explicitly said that you want to return reference .. you do not want to copy the object. It does not matter what I think about copies, it is about intent. And the intent was return a reference which can silently result in unintended code because you have two places to make a mistake instead of one.

    • @keris3920
      @keris3920 Місяць тому

      @@jakubskopal43 organize your functions in the opposite order of which they're used so that the compiler complains about deducing the return type of the function before it's declared. That way you will get a compile error when you forget the return type. Problem solved.

  • @KhalilEstell
    @KhalilEstell Місяць тому

    This was great! I like the pattern and it looks very straight forward.

  • @TheSulross
    @TheSulross Місяць тому

    Swift enum and its pattern matching is one of the more attractive features of that language

  • @GeorgeTsiros
    @GeorgeTsiros Місяць тому

    is this "reflection at home"?

  • @mworld
    @mworld Місяць тому

    I implemented ChaiScript into a game I was creating. Unfortunately it remembers declarations and fails to execute a second+ time. Needs a reset on the chai object. Using Lua + Sol works in the way I expected.

    • @cppweekly
      @cppweekly  Місяць тому

      yeah, that was a feature that was considered awhile back but never implemented.

  • @darkmagic543
    @darkmagic543 Місяць тому +9

    Oh that's a really cool pattern. On a personal note, I just don't like the trailing return types, It's just confusing when you see auto and sometimes scroll very far just to find the actual return type. I prefer wiriting everything before the return type on the line above.

    • @cppweekly
      @cppweekly  Місяць тому

      But if you get used to it you don't like the old school way.
      This is the kind of thing I'm pretty agnostic on.

  • @roco65tube
    @roco65tube Місяць тому

    thanks for the video Jason! It would have been great to see the reasoning why multiple disptach is not natively supported in c++

    • @cppweekly
      @cppweekly  Місяць тому

      I think it's the kind of thing we're "waiting for pattern matching for" (if that ever comes...)

  • @dadisuperman3472
    @dadisuperman3472 Місяць тому

    Available starting which version of C++

    • @oschonrock
      @oschonrock Місяць тому

      c++17, I think

    • @AruisDante
      @AruisDante Місяць тому +2

      std::variant and std::visit were added in 17.

    • @oschonrock
      @oschonrock Місяць тому

      @@AruisDante
      @dadisuperman3472
      yes 17. But you need the to deduction guide for the "visitor struct" option until c++20

  • @Voy2378
    @Voy2378 Місяць тому

    it is so cringy that they used [[nodiscard]] instead of [[use]] because probably 0.0001% of lines of code have variable named use.

    • @spacey6960
      @spacey6960 Місяць тому

      [[nodiscard]] makes more sense to me, and i ve never even used it. [[use]] sounds like a suggestion, not an obligation. Maybe something like [[mustuse]] would have been just as good

  • @milasudril
    @milasudril Місяць тому +1

    The proper way to do it is to use the visitor pattern

  • @sumitsatpute8906
    @sumitsatpute8906 Місяць тому

    I can use this in our code but I will get a review comments 😂😂