It's worth writing functions that accept a std::istream or std::ostream for
reading and writing (respectively), rather than hard-coding a file name. This makes for easier testing, as we can write to a std::stringstream rather than assuming we're able to write to Input.txt in the current working directory.
It's also better for your production code, as we ...
A few things I would change are:
Some private methods tend to check for null on their arguments, even if you control, what they are being called with. Unless I plan to call with NULL, I'd remove those checks.
The exception methods might either provide no message, as they do not help the caller more than the standard message of the exception or provide ...
Avoid using too much namespace
You risk having identical names mapped onto each other. Either be more selective in what you are using, or create short aliases if you want to avoid typing long namespace names, like:
namespace fs = ghc::filesystem;
You already ran into this problem with is_empty().
Don't #include headers you don't need
In wrap.h, you #...
Like you noticed, no need to use multiple loops when you can do everything in one function and loop only once.
Aside from that, there are many small things that can be improved with this script:
This script doesn't work if the script is not in the same directory as the source directory. Correct if me I am wrong, but this is what I encountered when I tested ...