Variadic Macros
     Variadic macros are supported by a number of compilers. They are
      macros of the form: 
    
      #define SOME_MACRO(ZeroOrMoreParameters,...) macro expansion possible specifying __VA_ARGS__
     
     The '...' in the parameter list represents the variadic data when the
      macro is invoked and the __VA_ARGS__ in the expansion represents the
      variadic data in the expansion of the macro. Variadic data is of the form
      of 1 or more preprocessor tokens separated by commas.
      
      The '...' must be the last parameter in the macro definition and there may
      be 0 or more non-variadic parameters preceding it.
      
      In the expansion of the macro __VA_ARGS__ may be specified 0 or more times
      to represent the variadic data. The variadic data in the expansion is a
      comma separated list of preprocessor tokens representing the variadic data
      which the invoker of the macro enters as the last arguments to the macro.
    
    Example - Creating and invoking a variadic macro.
    
      #define INITIALIZE_INT_ARRAY(array_name,...) \ 
 static int array_name[] = { __VA_ARGS__ }; \ 
 /**/
 INITIALIZE_INT_ARRAY(myname,45,789,33510,9346,2)
     
     Preprocessor
        Library Support
      
    The library offers support for variadic macros for those
      compilers
      which support the feature. The library can automatically detect whether
      a compiler supports variadic macros and sets the macro
      BOOST_PP_VARIADICS accordingly to 1 if the compiler supports variadic
      macros or 0 if the compiler does not support variadic macros.
      
      The end-user can #define BOOST_PP_VARIADICS to 1 or 0 himself in a
      translation unit, before including any preprocessor header files, to
      prevent the library from attempting to detect whether the compiler
      supports variadic macros. This has the effect of manually turning on or
      off variadic macro support in the library. Of course if one manually
      turns on variadic macro support in the library, and one's compiler does
      not support variadic macros, functionality in the library which uses
      variadic macros will fail with error messages from the compiler.
      
      When BOOST_PP_VARIADICS is 1, the library offers some extended
      functionality
      by using variadic macros, and also offers extended support for working
      with variadic data.
      
Visual C++ has a 
      few quirks related to variadic macros which require the end-user to code
      slightly differently. When BOOST_PP_VARIADICS is 1 and Visual C++ is the
      compiler BOOST_PP_VARIADICS_MSVC is 1, else when BOOST_PP_VARIADICS is 1
      and Visual C++ is not the compiler BOOST_PP_VARIADICS_MSVC is 0. When
      BOOST_PP_VARIADICS is 0 then BOOST_PP_VARIADICS_MSVC is not defined.
      In this way the end-user, when using variadic macros, can test for the
      presence of Visual C++ as the compiler and code accordingly.
      
      Support for working with variadic
      data is largely centered on being able to convert variadic data to
      other library data types, since the
      functionality for working with those Boost preprocessor library data
      types is much greater than that for working with variadic data directly.
    
Notation For Variadic Macros
    
    In the documentation, headers which have variadic macros,
      and
      variadic macros themselves, have a notation of '(v)' appended to them.
      For the variadic macros themselves this signifies that
      BOOST_PP_VARIADICS must be 1 for those variadic macros to be usable.
      For variadic macros which have a non-variadic equivalent, the
      non-variadic equivalent will be used if BOOST_PP_VARIADICS is set to 0.
    
    Extended Functionality Using Variadic Macros
    
    Some macros in the library offer extended
      functionality through the use of variadic macros.
      
      The variadic macro version offers the same functionality
      as the non-variadic version, but because of the ability of the variadic
      parameters to encompass a variable number of arguments, it also offers
      an enhanced syntax using the same macro name.
      
      The macros in the library which offer this enhanced functionality are
      all
      centered on tuple manipulation. With variadic
      macros it is
      possible to
      manipulate tuples without having to know the size of the tuple. So
      while the invoker can still specify the size when using tuple macro
      functionality, there are variadic versions of each of the tuple macros,
      with the exact same name as the non-variadic macro, where the size need
      not be specified.
    
    Extended Support For Variadic Data
    The library offers extended support for working with
      variadic data
      which goes beyond the functionality offered by the C++ specification
      for variadic macros. It does this through preprocessor programming and
      by using some of the other functionality in the library itself. Header
      and macro names
      in the library which offer extended support for working with variadic
      data, and need the compiler to support variadic macros, are marked with
      a (v) to indicate a variadic macro.
      
      The form of the functionality which the library offers is centered on
      two macros which work with variadic data itself, and a set of macros
      which convert between variadic data and other library data
      types.
      
      The two macros are BOOST_PP_VARIADIC_ELEM and BOOST_PP_VARIADIC_SIZE,
      which respectively return a particular token of variadic data and the
      number of tokens of variadic data.
      
      The macros for converting variadic data to the library's data types are
      BOOST_PP_VARIADIC_TO_ARRAY, BOOST_PP_VARIADIC_TO_LIST,
      BOOST_PP_VARIADIC_TO_SEQ, and BOOST_PP_VARIADIC_TO_TUPLE.
      
      All of these macros need compiler support for variadic data and only
      exist if BOOST_PP_VARIADICS is 1. 
      
      The remaining four macros, which convert from a library data type
      to comma-separated preprocessor tokens, which is the form of
      variadic data, do not need compiler support for variadic
      macros. These functions are BOOST_PP_ARRAY_ENUM, BOOST_PP_LIST_ENUM,
      BOOST_PP_SEQ_ENUM, and BOOST_PP_TUPLE_ENUM. However if one wishes to
      use this variadic data reliably as arguments to other macros, one needs
      variadic macro support.
    
     Using a Tuple Instead of an Array
    
    An array as a preprocessor data type is a two-element tuple where the
      first element is the array size and the second element is a tuple which
      constitutes the array data. Because a tuple knows its own size when the
      compiler supports variadic macros, there is no reason to use the array preprocessor
      data type as opposed to the tuple preprocessor data type; the tuple data
      type now has all of the functionality which the array data type has and is
      syntactically easier to use. With variadic macro support, which is now
      officially part of the latest C++ standard, the preprocessor array data
      type is essentially obsolete for conforming C++ compilers. Only if your
      compiler does not support variadic macros is the preprocessor array data
      type still useful.
    Using Variadic Data
    Variadic data exists in the
      form of comma-separated preprocessor tokens. This is the case whether
      the variadic data comes from the __VA_ARGS__ of a variadic macro, from
      the conversion of a library's data type to variadic data, or the
      manual construction of comma-separated preprocessing tokens by the
      programmer writing a macro.
      
      The easiest way to work with
      variadic data internally is to convert it to a library data type.
      Library data types, whether an array, list,
      sequence,
      or tuple, have a rich set of functionality for
      manipulating
      data whereas
      variadic data functionality in the library only allows one to access
      the variadic data as a whole or to access a single token of the
      variadic data at a time.
      
      The user of the library still may
      choose to pass variadic data back into internal macros rather than
      convert it to other library data types. There is no problem passing
      variadic data as a whole to variadic macros as the last parameter of
      the macro. However: 
      
      Attempting to pass
        variadic data as a
        whole directly into a non-variadic macro is not guaranteed to work and
        may fail.
      
      This occurs because of a preprocessor weakness in a number
      of compilers, currently most notably Visual C++. Even passing variadic
      data as arguments to a non-variadic macro, when it is not represented
      in
      the form of  __VA_ARGS__, may fail with certain compilers.
      
      What follows are very simple examples, showing how variadic data can be
      passed to a non-variadic macro.
      
      First an example of what NOT to do.
    
    Example - Passing variadic data as a whole to a
        non-variadic
        macro. DO NOT DO.
    
      #define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)
#define VAR_MACRO(...) __VA_ARGS__
/* The following should not be done and is not guaranteed to work with compilers. */
int xx = MACRO_ARG_2(VAR_MACRO(2,3));
     
     There are two ways to pass variadic data to a non-variadic
      macro.
      The
      first of these is to pass the individual tokens of the variadic data
      separately to the non-variadic macro using the BOOST_PP_VARIADIC_ELEM
      macro in the library.
    
    Example - Passing individual variadic data tokens to
        a
        non-variadic macro.
      
    
      #define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)
#define VAR_MACRO(...) __VA_ARGS__
/* The following will work correctly */
int xx = MACRO_ARG_2
 (
 BOOST_PP_VARIADIC_ELEM(0,VAR_MACRO(2,3)),
 BOOST_PP_VARIADIC_ELEM(1,VAR_MACRO(2,3))
 );
     
    The second way is to use a macro in the library called
      BOOST_PP_OVERLOAD.
      This macro allows one to "overload" a variadic macro to non-variadic
      macros of different numbers of parameters, using a common prefix.
    
    Example - Passing variadic data as a whole to
        BOOST_PP_OVERLOAD
        and on to a non-variadic macro.
      
    
      #define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)
#define VAR_MACRO(...) __VA_ARGS__
/* The following will work correctly */
int xx = BOOST_PP_OVERLOAD(MACRO_ARG_,VAR_MACRO(2,3))(VAR_MACRO(2,3));
/* For Visual C++ it is necessary to do this */
int xx = 
BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_ARG_,VAR_MACRO(2,3))(VAR_MACRO(2,3)),BOOST_PP_EMPTY());
     
    
    Although these techniques will work when passing variadic
      data to
      non-variadic macros, it is much better and less problematical to
      work internally with the existing library data types and to only use
      variadic
      macros as an interface for end-users when there is a need to have a
      macro which takes a
      variable number of parameters.
    
    See Also
    
    
     © Copyright
        Edward Diener
        2011,2013,2016