Rust development is Java-esque in some ways, I think that is a fair characterization, but the Rust language is noticeably less expressive than C++. The relative lack of expressiveness has been a stumbling block for use in some domains, because modern C++ implementations require a fraction of the code to do the same thing. This disparity doesn't show up for all types of code, so it is not uncommon to see both Rust and C++ used in the same org depending on what the code is trying to do. They have different strengths.
Java and Rust have similar goals, you can see it in the design of the language and the ecosystem. I lived in the early Java ecosystem and the Rust ecosystem has a similar vibe. They were both attacking the same problem but were are products of their respective times. The key difference is that Rust was able to learn from Java's mistakes and make ambitious technical bets that would not have been feasible at the time Java was designed. Java was invented when most serious applications were written in C and sometimes early versions of C++. It eliminated much of the conceptual complexity that made it difficult for all but the best developers to be productive in C or C++. In this Java was a massive success, it was easy to scale development even if you didn't have the world's best engineers.
Java's mistake is that they went much too far when they nerfed the language. For highly skilled developers that could write robust C or C++, the poor expressiveness of Java made many easy things difficult or impossible. It was clearly a language designed with business logic in mind, any systems-y software was an afterthought. The release of C++11 ushered in the era of "modern" C++, killing Java's momentum in the systems-y software space.
Rust, in my view, attempts to solve the same abstract problem as Java -- we will never produce enough developers that are competent at writing C or C++. Rust talks about "safety by design" in the same way Java did when it was first released. However, it does so without being so limited that highly skilled software engineers will find the language unusable or giving up so much runtime performance that the operational economics are poor. In my mental taxonomy, Rust is pretty close to what Java intended to be but then never quite delivered on.
I'd say both Rust and C++ trade blows when it comes to expressiveness. You know Rust already, so I'm not going to try sell you how powerful macros can be (see SQLx's ability to compile-time check SQL queries).
And indeed C++ templates are a lot more like Rust macros than Rust generics: They're turing-complete.
Joint with some interesting language choices like SFINAE (substitution failure is not an error), you end up with the ability to specialize functions, methods and whole classes in C++.
You can also have functions that return different types.
C++ templates work like duck-typing within a static language: In Rust you need to say what traits your generics need to support. In C++ it will try and substitute and if it fails (say, because T doesn't support the required methods) it will try another substitution until none are left.
If none of the substitutions work, you will be shown ALL of them in error reporting: This is what leads to pages and pages of compile errors of single-character typos in C++.
Templates are really cool, but also pretty confusing when reading code since you're in a guessing game of what types will fit the constraints imposed by the _implementation_ of the function.
From C++20 there's concepts to make templates work a little smoother.
There's been whole books written about how to abuse templates: these are pre-requisite knowledge when working in large codebases.
The big one is metaprogramming. Most people that have never really used it grok how powerful (and clean and maintainable) it has become in recent versions of C++. I work on a few different C++20 code bases and the amount of code that is no longer written because it is generated at compile-time with rigorous type safety is brilliant. It goes well beyond vanilla templating, you can essentially build a DSL for the application domain.
Another one, with a more limited audience, is data models where object ownership and lifetimes are inherently indeterminate at compile-time. Since C++ allows you to design your own safety models, since they are opt-in and not built into the compiler, you can provide traditional ownership semantics (e.g. the equivalent of std::unique_ptr) without exposing the mechanics of how ownership or lifetimes are resolved at runtime. Metaprogramming plays a significant role in making this transparent.
Those are the two the matter the most for my purposes. They save an enormous amount of code and bugs. Rust has a litany of other gaps (lack of proper thread local, placement new, et al) but I don't run into those cases routinely.
The data structure thing you mention would be annoying but to be honest I rarely design data structures like this. For performance, most data structures tend to rely on clever abuse of arrays.