261 lines
14 KiB
HTML
261 lines
14 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||
<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 nearly all compilers.
|
||
Variadic macros 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 requires support for variadic macros for all
|
||
compilers using the library. This usually means that compilation
|
||
at the C level is C99 or higher and that compilation at the C++
|
||
level is C++11 or higher. Many C++ compilers support variadic
|
||
macros at the C++98/C++03 level as long as strict compliance is
|
||
not turned on for those compilers at that level. In particular
|
||
both the gcc and clang compilers will support variadic macros at
|
||
the C++98/C++03 levels as long as strict ANSI compliance is not
|
||
turned on at that level. For those compilers this largely means
|
||
that the <code>-pedantic</code> or <code>-pedantic-errors</code>
|
||
option is not used at the C++98/C++03 level of compilation. Boost
|
||
C++ is deprecating compiling Boost libraries at the C++98/C++03
|
||
level, so if you must still use this library at that level be
|
||
aware of these aforementioned caveats.<br>
|
||
<br>
|
||
<a name="vmvcquirk"></a>Visual C++'s default preprocessor has a
|
||
few quirks related to variadic macros which require the end-user
|
||
to code slightly differently. When Visual C++'s default
|
||
preprocessor is being used BOOST_PP_VARIADICS_MSVC is 1, otherwise
|
||
it is 0. In this way the end-user can test for the presence of
|
||
Visual C++'s default preprocessor 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>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 extended functionality because
|
||
of the ability of the variadic parameters to encompass a variable
|
||
number of arguments. The library has functionality which can know
|
||
the number of variadic arguments passed when invoking a variadic
|
||
macro. This allows the same variadic macro to work with different
|
||
numbers of parameters, therefore providing more than one
|
||
syntactical equivalent for 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 syntactical
|
||
versions of each of the tuple macros 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.<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>
|
||
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 use variadic macros. These functions are
|
||
BOOST_PP_ARRAY_ENUM, BOOST_PP_LIST_ENUM, BOOST_PP_SEQ_ENUM, and
|
||
BOOST_PP_TUPLE_ENUM. You can use this variadic data reliably as
|
||
arguments to other macros using variadic macro support.<br>
|
||
</div>
|
||
<h4><a name="C20_Support_For_Variadic_Macros"></a>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>
|
||
<br>
|
||
When the __VA_OPT__ construct is supported in C++20 mode the
|
||
variadic data passed to the variadic macros and to
|
||
BOOST_PP_OVERLOAD can be empty, otherwise when not in this mode
|
||
variadic data passed to the variadic macros should never be empty.
|
||
In this C+++20 mode invoking BOOST_PP_VARIADIC_SIZE with empty
|
||
data expands to 0, invoking BOOST_PP_VARIADIC_TO_ARRAY with empty
|
||
data expands to the empty array '(0,())', invoking
|
||
BOOST_PP_VARIADIC_TO_LIST with empty data expands to the empty
|
||
list 'BOOST_PP_NIL', and invoking BOOST_PP_OVERLOAD with empty
|
||
data creates an overload name with 0 appended. Similarly in this
|
||
C++20 mode passing an empty array '(0,())' to BOOST_PP_ARRAY_ENUM
|
||
expands to empty variadic data and passing an empty list
|
||
'BOOST_PP_NIL' to BOOST_PP_LIST_ENUM also expands to empty
|
||
variadic data. Neither a seq or a tuple can be empty so passing
|
||
empty variadic data to either BOOST_PP_VARIADIC_TO_SEQ or
|
||
BOOST_PP_VARIADIC_TO_TUPLE is erroneous. Likewise passing empty
|
||
data to BOOST_PP_VARIADIC_ELEM is always erroneous since there are
|
||
no tokens of variadic data to access.<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 because of compiler support for 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. The preprocessor array data type
|
||
is essentially obsolete for modern C++ compilers.</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++'s default
|
||
preprocessor. 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++'s default preprocessor 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>
|
||
<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="../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><EFBFBD> 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>
|