First, we need a base definition for construct<T>:

template <class T> struct construct
  outcome::result<T> operator()() const noexcept
  {  //
    static_assert(!std::is_same<T, T>::value, "construct<T>() was not specialised for the type T supplied");
View this code on Github

This fails a static assert if the type is ever instantiated unspecialised.

We then specialise for construct<file_handle>:

template <> struct construct<file_handle>
  file_handle::path_type _path;
  file_handle::mode _mode{file_handle::mode::read};
  // Any other args, default initialised if necessary, follow here ...

  outcome::result<file_handle> operator()() const noexcept { return file_handle::file(std::move(_path)); }
View this code on Github

Because this is a struct, we can list initialise construct, and use default member initialisers to implement default arguments. This can get you surprisingly far before you need to start writing custom constructors.

But in more complex code, you will usually provide all the initialisation overloads that you would for the constructors of your main type. You then implement a single phase 2 constructing function which accepts construct<YOURTYPE> as input, and construct solely from that source.