However, I'd say Rust traits are more elegant in unifying what are two separate worlds in C++:
(1) calling virtual methods on a base class pointer, which can be (usually is) dispatched at runtime, but thus can't support methods with generic parameters or having a 'virtual type' (instead of a method), and
(2) accessing members of template parameter classes, including (possibly generic) methods, constants, typedefs, etc. - much more flexible, but doesn't work at runtime. Also dynamically typed, for better or worse; Rust thinks worse.
In Rust, (1) is a trait object, and (2) can be done with a generic parameter specified to implement a certain trait with methods, associated types, and constants. Rust's compiler doesn't try to be magic (unlike, say, Haskell), and so traits with generic methods and such can't be made into trait objects, but they're still traits - they feel like the same basic kind of thing.
You can do the same in C, for that matter. Or in assembly.
The reason we still come up with new languages is so that you can write code that conforms to certain patterns easily.
You cannot, for instance, create a new abstract base class and have a pre-existing class in someone else's header implement your abstract base class, such that a pointer to that pre-existing class can be dynamic_cast to your class.
Because that statement refers to C++ semantics, not your ability to compute things, it's not affected by the claim of Turing-completeness.
Sure you can, for some value of base class and cast. You might not be able to use particular keywords, but data is data and math is math. You might not be able to use the built-in type system to do it.
C and javascript programmers write their own inheritance-based type systems all the time. And anything you can do in C, you can do in C++ if you really want to.
In the case of C, yes you can do that, and where performance is critical you might prefer to do it, but it's obviously not going to be your first choice if you have any sense.