123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- <html>
- <head>
- <meta content="text/html; charset=windows-1252" http-equiv="content-type">
- <title>variadic_macros.html</title>
- <link rel="stylesheet" type="text/css" href="../styles.css">
- <style>
- u { font-weight: normal; text-decoration: none; }
- </style>
- </head>
- <body>
- <h4>Variadic Macros</h4>
- <div> Variadic macros are supported by a number of compilers. They are
- macros of the form: </div>
- <div class="code">
- <pre>#define SOME_MACRO(ZeroOrMoreParameters,...) macro expansion possible specifying __VA_ARGS__</pre>
- </div>
- <div> 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.<br>
- <br>
- The '...' must be the last parameter in the macro definition and there may
- be 0 or more non-variadic parameters preceding it.<br>
- <br>
- 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.<br>
- </div>
- <h4>Example<u> - Creating and invoking a variadic macro.</u></h4>
- <div class="code">
- <pre>#define INITIALIZE_INT_ARRAY(array_name,...) \ <br> static int array_name[] = { __VA_ARGS__ }; \ <br> /**/<br><br> INITIALIZE_INT_ARRAY(myname,45,789,33510,9346,2)</pre>
- </div>
- <u> <span style="font-weight: bold;">Preprocessor
- Library Support<br>
- </span></u>
- <div>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.<br>
- <br>
- 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.<br>
- <br>
- 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.<br><br>
- <a name="vmvcquirk"></a>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.<br>
- <br>
- 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.<br>
- </div>
- <a name="VNotation"></a>
- <h4>Notation For Variadic Macros<br>
- </h4>
- <div>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.
- </div>
- <h4>Extended Functionality Using Variadic Macros<br>
- </h4>
- <div>Some macros in the library offer extended
- functionality through the use of variadic macros.<br>
- <br>
- 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.<br>
- <br>
- The macros in the library which offer this enhanced functionality are
- all
- centered on <i>tuple</i> 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.<br>
- </div>
- <h4>Extended Support For Variadic Data</h4>
- <div>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)<sup> </sup>to indicate a variadic macro.<br>
- <br>
- 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.<br>
- <br>
- 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.<br>
- <br>
- 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.<br>
- <br>
- All of these macros need compiler support for variadic data and only
- exist if BOOST_PP_VARIADICS is 1. <br>
- <br>
- 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.<br>
- </div>
- <h4>C++20 Support For Variadic Macros</h4>
- <div>
- In the C++20 specification there is a new construct which can be
- used in the expansion of a variadic macro, called __VA_OPT__. This
- construct when used in the expansion of a variadic macro is followed
- by an opening paranthesis ('('), preprocessor data, and a closing
- parenthesis ('}'). When the variadic data passed by the invocation
- of a variadic macro is empty, this new construct expands to nothing.
- When the variadic data passed by the invocation of a variadic macro
- is not empty, this new construct expands to the preprocessor data
- between its opening and closing parentheses.
- <br><br>
- This library offers support for this new C++20 construct by automatically
- detecting whether this new construct is supported by the compiler's
- preprocessor when using the library. The library macro which detects
- support for the __VA_OPT__ construct is called BOOST_PP_VARIADIC_HAS_OPT.
- This is a function-like macro which takes no parameters and returns
- 1 if the compiler is working in C++20 mode and supports the __VA_OPT__
- construct, while otherwise it returns 0.
- <br>
- </div>
- <u style="font-weight: bold;"> Using a Tuple Instead of an Array<br>
- </u>
- <div>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.</div>
- <u style="font-weight: bold;">Using Variadic Data</u>
- <div>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.<br>
- <br>
- The easiest way to work with
- variadic data internally is to convert it to a library data type.
- Library data types, whether an <i>array</i>, <i>list</i>,
- <i>sequence</i>,
- or <i>tuple</i>, 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.<br>
- <br>
- 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: <br>
- <br>
- <span style="font-weight: bold;">Attempting to pass
- variadic data as a
- whole directly into a non-variadic macro is not guaranteed to work and
- may fail.<br>
- </span><br>
- 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.<br>
- <br>
- What follows are very simple examples, showing how variadic data can be
- passed to a non-variadic macro.<br>
- <br>
- First an example of what NOT to do.<br>
- </div>
- <h4>Example<u> - Passing variadic data as a whole to a
- non-variadic
- macro. DO NOT DO.</u></h4>
- <div class="code">
- <pre>#define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)<br>#define VAR_MACRO(...) __VA_ARGS__<br><br>/* The following should not be done and is not guaranteed to work with compilers. */<br><br><span
- style="font-weight: bold;"><span style="font-family: monospace;"></span></span>int xx = MACRO_ARG_2(VAR_MACRO(2,3));</pre>
- </div>
- <div> 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.<br>
- </div>
- <h4>Example<u> - Passing individual variadic data tokens to
- a
- non-variadic macro.<br>
- </u></h4>
- <div class="code">
- <pre>#define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)<br>#define VAR_MACRO(...) __VA_ARGS__<br><br>/* The following will work correctly */<br><br>int xx = MACRO_ARG_2<br> (<br> BOOST_PP_VARIADIC_ELEM(0,VAR_MACRO(2,3)),<br> BOOST_PP_VARIADIC_ELEM(1,VAR_MACRO(2,3))<br> );</pre>
- </div>
- <div>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.
- </div>
- <h4>Example<u> - Passing variadic data as a whole to
- BOOST_PP_OVERLOAD
- and on to a non-variadic macro.<br>
- </u></h4>
- <div class="code">
- <pre>#define MACRO_ARG_2(x,y) BOOST_PP_ADD(x,y)<br>#define VAR_MACRO(...) __VA_ARGS__<br><br>/* The following will work correctly */<br><br>int xx = BOOST_PP_OVERLOAD(MACRO_ARG_,VAR_MACRO(2,3))(VAR_MACRO(2,3));<br><br>/* For Visual C++ it is necessary to do this */<br><br>int xx = <br>BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_ARG_,VAR_MACRO(2,3))(VAR_MACRO(2,3)),BOOST_PP_EMPTY());</pre>
- </div>
- <br>
- <div>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.<br>
- </div>
- <b>See</b> <b>Also</b><br>
- <ul>
- <li><a href="../ref/variadics.html">BOOST_PP_VARIADICS</a></li>
- <li><a href="../headers/tuple.html">Tuple Macros</a><br>
- </li>
- <li><a href="../headers/variadic.html">Variadic
- Macros<br>
- </a></li>
- <li><a href="../ref/array_enum.html">BOOST_PP_ARRAY_ENUM</a></li>
- <li><a href="../ref/list_enum_r.html">BOOST_PP_LIST_ENUM</a></li>
- <li><a href="../ref/seq_enum.html">BOOST_PP_SEQ_ENUM</a></li>
- <li><a href="../ref/tuple_enum.html">BOOST_PP_TUPLE_ENUM</a></li>
- <li><a href="../ref/overload.html">BOOST_PP_OVERLOAD</a></li>
- </ul>
- <hr size="1">
- <div style="margin-left: 0px;"> <i>© Copyright
- Edward Diener
- 2011,2013,2016</i> </div>
- <div style="margin-left: 0px;">
- <p><small>Distributed under the Boost Software License,
- Version 1.0.
- (See accompanying file <a href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a>
- or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</small></p>
- </div>
- </body>
- </html>
|