construct

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

template <class T> struct make
{
  outcome::result<T> operator()() const noexcept
  {                                            //
    static_assert(!std::is_same<T, T>::value,  //
                  "make<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 make<file_handle>:

template <> struct make<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 make, 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 make<YOURTYPE> as input, and construct solely from that source.