I think we're agreeing with each other here, but just to beat a dead horse... don't reflect stuff like that. There's no reason to automatically reflect every hash table. I'm not even sure how'd you do that in C++ without using an external tool that intentionally scans for template instantiations which would be insanely difficult if you're not plugging into Clang or the like.
You should though follow the rule of reflecting only what you need.
You write there is no reason to do it.
You write that you should only reflect what you need.
So that means we are still in disagreement. I feel both these statements are incorrect.
For lack of another authoritative definition, I'll use the one from Wikipedia: Reflection allows inspection of classes, interfaces, fields and methods at runtime without knowing the names of the interfaces, fields, methods at compile time. It also allows instantiation of new objects and invocation of methods.
Reflection does not mean partial metadata, knowing only a part of the interfaces, a few of the fields, a subset of the methods, or invocation of the methods the linker happened to leave in place. Reflection means you can programatically access another system and completely reuse the entire functionality of classes and other parts..
In modern languages there is a very strong, compelling, and language-mandated reason to export every part of the public interface. Modern reflection mechanisms provide the complete functionality to any program that is allowed to observe or modify the system.
In C++ there is a language-preferred reason not to expose anything. The overhead and additional costs involved are exactly the reason the language does not want it.
This is one of the radical differences between what modern languages use for reflection and what older languages do.
More realistic systems would reflect only...
That is where I strongly disagree. Your "more realistic" means "a tiny piece of support compared to others".
Reflection in modern languages is very different from, and incompatible with, the old compilation model used by C and C++. Microsoft has invested a fortune into it building C++/CLI. Even after spending untold millions on the system across more than a decade, it still only partially works and they cannot get it to the same level of quality found in any modern language.
Large ecosystems have developed around reflection, with plugin architectures and external modifications being some of the biggest benefactors.
This is one of the big pieces of functionality that helps other languages advance far beyond C++ outside of systems-level work, and is a painful hole when doing systems work when your system must integrate with other systems. Back in the mid to late 1990s COM objects and DCOM objects became popular and profitable, as businesses could get components, drop them into their programs, and gain programmatic access and interoperability. There was (and still is) some overhead in figuring out exactly what should be exposed and how to expose it. Then there was an explosion of other languages with reflection. That is available for free with modern languages. Now in these modern languages you can pull down just about any functionality you want from any of a large number of public repositories, download only the final executable/library build, and have full access to everything you would have without need source, without needing to rebuild with different compiler options, without needing to account for ST/MT versions, without needing to account for dependencies.
C++ is a wonderful language for systems-level work and HPC because of the level it works at. But with an ever-expanding collection existing engines and tools, the lack of reflection continues to grow as one of C++'s serious flaws and missing features. The cost and effort of making a C++ program that plays well with others is painfully high. Every time there is a new library or new engine, or even an update to an existing component you've integrated into your library, the flaw becomes that much more apparent. In reflection-supporting languages you download a new final build and verify in the documentation that the public interface has not changed in breaking ways. In C++ such a change can require several days of integration efforts.
Like you, I've worked with many enormous code bases. I've maintained build systems, run the integration of many working parts, and even for one game cycle had the horrible job of keeping a large collection of C++ libraries updated with EA's massive corporate collection of systems for all the libraries used by the game, the tools, the build chain, and everything else. I currently work for a different company doing similar things but with a mostly Java codebase. The ability to simply point to nexus and pull down the latest final build, and having programs designed to automatically bind with any build I specify... Well, that is me and our codebase relying on the modern reflection mechanisms. The build chain automatically notifies the team when updates are available, and if we chose to take the updates we can usually integrate them by typing in a new version number and telling the build server to run the test suite. Having seen what reflection enables, I hope to never again need to manage dependency trees as is still done in C++.
TL:DR: About the closest C++ can get to reflection is with COM objects or DLL exports or similar extracted or programmer-maintained systems. While these are useful alternative interfaces, they are worlds away from reflection as it is used everywhere.