P99

◆ P99_CALL_DEFARG

#define P99_CALL_DEFARG (   NAME,
  M,
  ... 
)    NAME(__VA_ARGS__)

Define a replacement macro for functions that can provide default arguments to the underlying real function.

This macro may be used for `overloading' system functions or functions that you define yourself. It is easiest to explain this with an example. The system function pthread_mutex_init is defined as follows:

int pthread_mutex_init(pthread_mutex_t *mut, pthread_mutexattr_t* attr);

Here the second argument is used to specify an `attribute' to the mutex mut. Most people don't use that functionality and therefore pthread_mutex_init accepts a null pointer constant as a replacement for attr. This might be annoying since the focus of the syntax is on the exception rather than on the main use: the programmer always has to remember this particular special case and give explicit 0's.

The following lines heal this.

P99_PROTOTYPE(int, pthread_mutex_init, pthread_mutex_t*, pthread_mutexattr_t const*);
#define pthread_mutex_init(...) P99_CALL_DEFARG(pthread_mutex_init, 2, __VA_ARGS__)
P99_DECLARE_DEFARG(pthread_mutex_init, , (pthread_mutexattr_t*)0);

This declares a macro pthread_mutex_init that resolves to the call of a real function to initialize a pthread_mutexattr_t*. If invoked with two arguments or more, the macro expansion just results in the usual call to the function.

If the initialization value for argument 1 is omitted (arguments count from 0) the default value of a null pointer constant is used. Valid use is

static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutexattr_t attr;
.
pthread_mutex_init(&mut, &attr); // full specification with attributes
pthread_mutex_init(&mut, 0); // still a valid form
// easy variant for everyday use, equivalent to the previous one
// Also function pointers can still be taken.
int (*myFunc)(pthread_mutex_t *, pthread_mutexattr_t*) = pthread_mutex_init;
Parameters
NAMEis the function to provide with default argument features.
Mis the number of arguments that a full call to NAME takes.
See also
P99_DECLARE_DEFARG
P99_PROTOTYPE

This macro is more flexible than the corresponding C++ feature of default arguments. It also lets you omit middle arguments.

More technically, for arguments that are omitted this just requires that NAME_defarg_M is defined for function NAME and M and that it is callable without arguments. This may just be a function (as implicitly defined by P99_DECLARE_DEFARG) or a macro. For the first case everything the function refers to must be declared at the point of its definition. For the second case, the macro is evaluated at the place of the call and could refer to local variables or anything you like.