Chapter 55. Optional function arguments

Index

Declaring an x::optional_args
Retrieving optional arguments
Optional arguments using reference wrappers
Using x::optional_arg_or

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} });
}

Declaring an 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<type> for each template parameter 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.

Note

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} );