The ability to forward declare nested classes is one of my motivations.
I wouldn’t go into the direction of requiring compilers to automatically just “find me the right header files” and not specify how that works.
If I may take the discussion around “#pragma once”, I would say that lose rules regarding how the magic happens is a recipe for disaster.
From my understanding you can actually do quite a lot without much magic.
I have found 2 categories of problems.
1. Non-aliased types. Where the forwarded type is the actual name of the type. It will be one of class, struct, or union, without needing to specify it as a class, struct, or union.
2. Aliased types. A type "defined" by using typedef or using.
1 is super easy, it looks like pretty much everything works, template, constexpr, function calls, etc... I haven't noticed a problem yet. Everything that you can do with a trivially forward declared type you would be able to do with this.
The only difference is you don’t have to specify class, struct, or union, it’s one of those 3.
2 is much more complicated, because the actual name will be different from the know name. (ex. std::string)
I think you can make function calls sort of work.
As long as function prototypes are defined with the same name as the alias name, it is trivial to resolve. For that you would need extra data in object files to keep track of aliases so that it can resolve the actual names when linking.
I think that information would also need to be transitive and passed around static libraries such that you can handle linking between multiple libraries, it’s more to track but looks doable.
The problem starts when functions parameters don't match the alias name, it is possible in some situations to resolve the right symbol from an alias look up, but it gets tricky when types are derived types, and you need to deal with promotion
rules. That may require some additional compile time code generation. But then again that doesn’t work with trivial forward declared types either.
For constexpr functions, you can make it work if the name used is the same (or a qualified version thereof), if it isn’t, then link time it would be to late to do anything.
I would be ok for this type of forward declaration to not work with function calls (either regular or constexpr/consteval) if the used type name in those functions is not the alias name or a qualified version of it, as long as it would
work if the name used is the alias name.
Templates would only work in 2 scenarios. If the template doesn’t have any specialization at all, or the specialization explicitly uses the alias name.
If the template provides any specialization and none of them explicitly uses the alias name, there’s no way for the compiler to know what code to generate because it can not tell if the alias name aliases any of the specializations provided.
It might be possible to do something with link time code generation, but I’m not going to advocate to hoist all of the code generation to link time. And, I would be ok if this wouldn’t work in this scenario either.