The example shows the use of variable parameters and default parameters in C++ functions

  • 2020-05-09 18:52:10
  • OfStack

A function that contains a list of variables
If the last member of the function declaration is an ellipsis (...) , the function declaration can take a variable number of parameters. In these cases, C++ only provides type checking for explicitly declared parameters. Even if the number and type of arguments are variable, you can use the variable argument list when you want to generalize a function. The series of functions is an example of a function that USES a variable argument list. printfargument declaration -- list
A function that contains arguments to a variable
To access the parameters after the declaration, use the macros contained in the standard inclusion file STDARG.H (described below).

A function declaration with a variable number of arguments requires at least one placeholder argument (even if it is not used). If this placeholder parameter is not provided, the remaining parameters cannot be accessed.
When arguments of type char are passed as variable arguments, they are converted to type int. Similarly, when arguments of type float are passed as variable arguments, they are converted to type double. Other types of parameters are limited by common integer and floating point promotions.

Use the ellipsis (...) in the parameter list To declare functions that require a list of variables. Use the types and macros described in the STDARG.H include file to access the parameters passed in the variable list. For more information about these macros, see va_arg, va_copy, va_end, va_start. (in the C runtime library documentation).
The following example demonstrates how to use macros with type 1 (declared in STDARG.H) : va_listva_endva_argva_start


// variable_argument_lists.cpp
#include <stdio.h>
#include <stdarg.h>

// Declaration, but not definition, of ShowVar.
void ShowVar( char *szTypes, ... );
int main() {
  ShowVar( "fcsi", 32.4f, 'a', "Test string", 4 );
}

// ShowVar takes a format string of the form
//  "ifcs", where each character specifies the
//  type of the argument in that position.
//
// i = int
// f = float
// c = char
// s = string (char *)
//
// Following the format specification is a variable 
// list of arguments. Each argument corresponds to 
// a format character in the format string to which 
// the szTypes parameter points 
void ShowVar( char *szTypes, ... ) {
  va_list vl;
  int i;

  // szTypes is the last argument specified; you must access 
  // all others using the variable-argument macros.
  va_start( vl, szTypes );

  // Step through the list.
  for( i = 0; szTypes[i] != '\0'; ++i ) {
   union Printable_t {
     int   i;
     float  f;
     char  c;
     char  *s;
   } Printable;

   switch( szTypes[i] ) {  // Type to expect.
     case 'i':
      Printable.i = va_arg( vl, int );
      printf_s( "%i\n", Printable.i );
     break;

     case 'f':
       Printable.f = va_arg( vl, double );
       printf_s( "%f\n", Printable.f );
     break;

     case 'c':
       Printable.c = va_arg( vl, char );
       printf_s( "%c\n", Printable.c );
     break;

     case 's':
       Printable.s = va_arg( vl, char * );
       printf_s( "%s\n", Printable.s );
     break;

     default:
     break;
   }
  }
  va_end( vl );
}
//Output: 
// 32.400002
// a
// Test string

The last example demonstrates the following important concepts:
Before accessing any variable parameter, you must establish a list token as a variable of type va_list. In the previous example, this tag was called vl.
Access each parameter using the va_arg macro. The va_arg macro must be told the type of parameter to retrieve so that it can transfer the correct number of bytes from the stack. If the type of size specified for va_arg is different from the type provided through the caller, the result is unpredictable.
The results obtained using the va_arg macro should be explicitly cast to the desired type.
The macro must be called to terminate mutable parameter processing. va_end


The default parameters
In many cases, functions have infrequently used arguments because the default is sufficient. To solve this problem, the default parameter tool allows you to specify only the parameters that make sense in a given call to a function. To illustrate this concept, consider the example shown in function overloading.


// Prototype three print functions.
int print( char *s );         // Print a string.
int print( double dvalue );      // Print a double.
int print( double dvalue, int prec ); // Print a double with a
// given precision.

In many applications, you can provide a reasonable default value for prec, eliminating the need for two functions:


// Prototype two print functions.
int print( char *s );          // Print a string.
int print( double dvalue, int prec=2 ); // Print a double with a
// given precision.

Slightly changed the implementation of the print function to reflect the fact that there is only one such function of type double:


// default_arguments.cpp
// compile with: /EHsc /c

// Print a double in specified precision.
// Positive numbers for precision indicate how many digits
// precision after the decimal point to show. Negative
// numbers for precision indicate where to round the number
// to the left of the decimal point.

#include <iostream>
#include <math.h>
using namespace std;

int print( double dvalue, int prec ) {
  // Use table-lookup for rounding/truncation.
  static const double rgPow10[] = { 
   10E-7, 10E-6, 10E-5, 10E-4, 10E-3, 10E-2, 10E-1, 10E0,
     10E1, 10E2, 10E3, 10E4, 10E5, 10E6
  };
  const int iPowZero = 6;
  // If precision out of range, just print the number.
  if( prec >= -6 && prec <= 7 )
   // Scale, truncate, then rescale.
   dvalue = floor( dvalue / rgPow10[iPowZero - prec] ) *
   rgPow10[iPowZero - prec];
  cout << dvalue << endl;
  return cout.good();
}

To call the new print function, use the following code:


print( d );  // Precision of 2 supplied by default argument.
print( d, 0 ); // Override default argument to achieve other
// results.

When using the default parameters, please note the following:
Default arguments are used only in function calls where trailing arguments are omitted - they must be the last arguments. Therefore, the following code is illegal:


int print( double dvalue = 0.0, int prec );

The default parameter cannot be redefined in a later declaration, even if the redefined parameter is the same as the original parameter. Therefore, the following code will generate an error:


// Prototype for print function.
int print( double dvalue, int prec = 2 );

...

// Definition for print function.
int print( double dvalue, int prec = 2 )
{
...
}

The problem with this code is that the function declaration in the definition redefines the default parameters for prec.
Later declarations can add additional default parameters.
You can provide default parameters for Pointers to functions. Such as:


int (*pShowIntVal)( int i = 0 );


Related articles: