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;
}
… 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;
}
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.