Upgrading the Filesystem TS

An Outcome based solution to the dual overload problem is straightforward:

namespace filesystem2
{
  // Error code + paths related to a failure. Also causes ADL discovery to check this namespace.
  struct failure_info
  {
    std::error_code ec;
    path path1, path2;
  };

  // Tell Outcome that failure_info is to be treated as a std::error_code
  inline const std::error_code &make_error_code(const failure_info &fi) { return fi.ec; }

  // Localise an outcome implementation specific to this namespace. Normally would just
  // be `result`, but for clarity we'll use `fs_result`.
  template <class T> using fs_result = outcome::result<T, failure_info>;

  /*! Copies the file at path `from` to path `to`.
  \returns Successful if file was successfully copied, otherwise the error code reported
  by the operating system plus a payload of the paths involved.
  \throws Never throws.
  */
  fs_result<void> copy_file(const path &from, const path &to) noexcept;
}
View this code on Github

Starting at the bottom, there is now a single copy_file() function which returns a fs_result<void>. As result is either successful or not, there is no longer any point in returning a boolean, so we simply return void on success. On failure, as the template alias fs_result<T> above it shows, we are returning a failure_info structure containing an error code and the same additional information as filesystem_error provides.

It is important to note that the fact that failure_info is defined in namespace filesystem2 is very important. This is because Outcome uses Argument Dependent Lookup (ADL) to find the make_error_code() function, as well as other customisation point free functions. In other words, only the namespaces as defined by ADL are searched when finding a free function telling us what to do for failure_info, which includes the namespace failure_info is declared into.