I wonder if there are many cases where C++ will devirtualize and Rust won't.
But then again Rust devs are more likely to use static dispatch via generics if performance is critical.
That's pretty powerful:
• any type can be used in dynamic contexts, e.g. implement Debug print for an int or a Point, without paying cost of a vtable for each instance.
• you don't rely on, and don't fight, devirtualization. You can decide to selectively use dynamic dispatch in some places to reduce code size, without committing to it everywhere.
• you can write your own trait with your own virtual methods for a foreign type, and the type doesn't have to opt-in to this.
Put another way, in C++ the dynamic dispatch is implicit, so you might write code which (read literally) has dynamic dispatch but the optimizer will devirtualize it. However in Rust dynamic dispatch is explicit, so, you just would not write the dynamic dispatch - it's not really relevant whether an optimizer would "fix" that if you went out of your way to get it wrong. It's an idiomatic difference I'd say.
I'm not sure I follow - pretty much 99% of usage of C++ in the last, like, 20 years has been around making sure that you get static dispatch with polymorphism through templates. It's exceedingly uncommon to see the `virtual` keyword unless you have, say, some DLL-based run-time plug-in system going on.