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_argsx::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
	types 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} );