Phase 3

We have built our first two phases of construction for file_handle, and for some users they might be happy writing:

  outcome::result<file_handle> fh1 = file_handle::file("hello" /*, file_handle::mode::read */);
  if(!fh1)
  {
    std::cerr << "Opening file 'hello' failed with " << fh1.error().message() << std::endl;
  }
View this code on Github

… and be done with it.

But wouldn’t it be nicer if we could instead write:

  outcome::result<file_handle> fh2 = make<file_handle>{"hello" /*, file_handle::mode::read */}();
  if(!fh2)
  {
    std::cerr << "Opening file 'hello' failed with " << fh2.error().message() << std::endl;
  }
View this code on Github

The eye is immediately drawn to the two-stage invocation pattern, so we are constructing a type make<file_handle> using the arguments with which we wish to invoke the file_handle constructor with, and then invoking the call operator on that make<file_handle> instance to do the actual construction.

It may seem a bit clunky to use brace initialisation for parameters followed by a “spurious” set of empty brackets, but we think that this is a better approach than alternatives. We shall briefly cover those at the end of this section.