Index
The
x::optional_args
template helps with implementing “optional” function
parameters; that is,
parameters that can be individually omitted when making a function call.
This is not the same as having
trailing parameters with default values. Any parameter can be optionally
omitted.
Overloading accomplishes the same
thing, except that overloading spirals out of control once the number of
optional parameter is more than one or two.
For example: if there are three parameters,
and each one is optional, that's eight overloaded declarations, for
every combination of a specified or an omitted parameter.
Here's an example of declaring a function with two optional parameters.
adjust_pos_or_size
()'s
optional_coords
parameter specifies two dimensional,
x
and y
,
set of coordinates; and
the optional_size
parameter specifies a width
and a height.
adjust_pos_or_size
() accepts either one of these
two parameters, or both. Or neither (effectively a no-op):
#include <x/optional_args.H> struct optional_coords { int x; int y; optional_coords(int x, int y) : x{x}, y{y} {} }; struct optional_size { int w; int h; optional_size(int w, int h) : w{w}, h{h} {} }; void adjust_pos_or_size(const x::optional_args<optional_coords, optional_size> &args) { do_adjust_pos_or_size(LIBCXX_NAMESPACE::optional_arg<optional_coords>(args), LIBCXX_NAMESPACE::optional_arg<optional_size>(args)); } void do_adjust_pos_or_size(const std::optional<optional_coords> &pos, const std::optional<optional_size> &size) { // ... } void adjust_pos_or_size_example() { adjust_pos_or_size({}); adjust_pos_or_size({ optional_coords{1,2} } ); adjust_pos_or_size({ optional_size{3,4} }); adjust_pos_or_size({ optional_coords{1,2}, optional_size{3,4} }); }
x::optional_args
x::optional_args<optional_coords, optional_size>
The x::optional_args
template takes a variadic list of
template parameters, and declares an
std::optional<
for each template parameter
type
>type
.
These optionals get initialized by parameters passed to
x::optional_args
constructor, in the
same order, but each individual
type
, if not passed, gets skipped and
the corresponding x::optional
becomes a
std::nullopt
.
Any
type
s must be passed to the constructor in the
same order as the template parameters. All four function calls in
the example above are valid. If both parameters exist,
both optional_coords
,
and optional_size
, they must appear in
template parameter order.
void adjust_pos_or_size(const x::optional_args<optional_coords, optional_size> &args) // ... adjust_pos_or_size({ optional_size{3,4} });
In this example, uniform initialization syntax constructs
adjust_pos_or_size
()'s
x::optional_args parameter
.
Alternatively, template forwarding removes the outer uniform
initialization layer from the function call:
template<typename ...Args> void adjust_pos_or_size(Args &&...params) { x::optional_args<optional_coords, optional_size> args{std::forward<Args>(params)...); // ... adjust_pos_or_size(optional_size{3,4}, optional_size{6,7} );