C# is often like Java but without taking a wrong turn when it came to type-erased generics, the generics are uncomplicated enough even if slightly less powerful than what you get with the full instantiation of C++.
C++ was severely lacking before reflection came along in 26, I'm actually writing some new reflection based libraries and it's mostly a joy and quite capable.
But C++ has so many outrightly dangerous semantics when it comes to writing secure code, the coping of pointing to realtime systems,etc as another security "dimension" doesn't hold when Rust,etc exist today.
C# is good in that it's "easy" yet the performance profile of the features allows optimized code to run far closer to C++/rust/etc in performance compared to Java,etc. (that said, a wast majority is probably running like Java due to programmer patterns, but not needing to drop down to another language when it's needed feels good).
If you want to do insane meta programming, you should look into Roslyn generators. It's like they added a robust code gen system to the language (even though its a compile stack feature). You basically get the full power of templates and macros but you get to use the target language (C#) instead of a bolted on macro or template language.
More generally, the fact that the C# compiler is implemented as library with easy support for runtime code generation is also a powerful feature that I've found to be incredibly useful in a variety of expected and unexpected ways.