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...
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!
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.
A very interesting modern implementation of double-dispatch. Thanks.
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; }
};
wow this looks very clean
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.
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;
}
Cool trick ^^
Very interesting! I hope i never see this in production code :D
not even a cpp dev but still watching Jason Turner. Keep this up man ❤❤
very nice.. although If I needed this in such an example, I would seriously question if I have the right design?
In that case, what design would you suggest for the example?
@@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`?
To me it's just an argument that we want pattern matching so we get this naturally when we need/want it.
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”.
Nice
would be nice to see if boost::variant2 generates better code than std::variant
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.
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.
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
@@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.
@@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.
@@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.
@@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.
This was great! I like the pattern and it looks very straight forward.
Swift enum and its pattern matching is one of the more attractive features of that language
is this "reflection at home"?
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.
yeah, that was a feature that was considered awhile back but never implemented.
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.
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.
thanks for the video Jason! It would have been great to see the reasoning why multiple disptach is not natively supported in c++
I think it's the kind of thing we're "waiting for pattern matching for" (if that ever comes...)
Available starting which version of C++
c++17, I think
std::variant and std::visit were added in 17.
@@AruisDante
@dadisuperman3472
yes 17. But you need the to deduction guide for the "visitor struct" option until c++20
it is so cringy that they used [[nodiscard]] instead of [[use]] because probably 0.0001% of lines of code have variable named use.
[[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
The proper way to do it is to use the visitor pattern
I can use this in our code but I will get a review comments 😂😂