When dealing with functions that have lots of optional parameters, or at least
for which resonable defaults are readily available, it's often a bit of a
frustration in C++. Generally defaults are specified during a function
declaration as in:

And then if we call BinarySearch with only one parameter then the call will
use the default values for the rest. But what if I want to specify custom
bound, and use the defaults for the other parameters? Admittedly, this is a
somewhat contrived example since bounds are less likely to be optional then
the others, and we could reorder them better going from most-likely-to-be-
specified to least, but it's easy to see how something more flexible would be
desirable.

Consider then the following two code snippets. Which is more readable?

I really like the way that optional arguments work in python with kwargs. I'd
love to have that same kind of functionality in C++.
kwargs.h
implements one mechanism of achieving this.

How does it work

kwargs takes advantage of variadic
templates in C++ to
build up a single data structure which contains all of the optional parameters
(I'll call this a "parameter pack"). Each optional parameter of type T is
stored in a structure of type Arg<tag,T> where tag is a unique numeric
identifier associated with a particular optional argument key.

The parameter pack data structure derives from Arg<tag,T> for each (tag,T)
pair that shows up in the list of optional arguments.

Overloading of the assignment (=) operator gives us an opportunity for
building the (tag,T) pairs within the parameter list of the function call.

Get it

Example

I'll conclude with an example usage:

#include#include "kwargs.h"// these are tags which will uniquely identify the arguments in a parameter// packenumKeys{c_tag,d_tag};// global symbols used as keys in list of kwargskw::Keyc_key;kw::Keyd_key;// a function taking kwargs parameter packtemplatevoidfoo(inta,intb,Args…kwargs){// first, we construct the parameter pack from the parameter packkw::ParamPackparams(kwargs…);std::cout<<"foo:\n--------"<<"\na: "<<a<<"\nb: "<<b// We can attempt to retrieve a key while providing a default fallback value.// If c_key is in kwargs then this will return the value associated with// that key, and will have the correct type. Note that the type of the default// parameter in this case is const char*.<<"\nc: "<<kw::Get(params,c_key,"null");// We can also do stuff conditionally based on whether or not arg exists in// the param pack. We still need to provide a default value, since we need to// know the return type of the Get function when the key is not in kwargs.// In this case, the default value wont ever be used at runtime.if(kw::ContainsTag::result){std::cout<<"\nd: "<<kw::Get(params,d_key,0);}std::cout<<"\n\n";}intmain(intargc,char**argv){foo(1,2);foo(1,2,c_key=3);foo(1,2,c_key=3,d_key=4);foo(1,2,d_key=4);}