Error handling and signals
There are two kinds of errors we need to deal with. The first kind are expected errors, such as files not being found or of an unrecognized format, and unexpected errors, where some operation lower down catastrophically fails for some unknown reason. We might also call these recoverable and unrecoverable errors, respectively. In both cases, we will use the logging framework to first report the error and, if necessary, terminate the application using std::exit as we did before. Ideally, we will report recoverable errors that happen lower down also using the spdlog functions, and only use the exception mechanism for unrecoverable errors.
When we’re writing the code for the other parts of this challenge, we can be careful to catch errors that are thrown in any library functions, where it is appropriate to do so. (Remember, we want errors that are unrecoverable to propagate outward and only be caught at the last level.) However, this still leaves...