Expanded emptiness explanation with the addition of the BOOST_PP_VA_OPT macro.

This commit is contained in:
Edward Diener
2019-11-02 23:58:29 -04:00
parent de49676452
commit b3036f1a63

View File

@ -1,21 +1,22 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <html>
<head> <head>
<meta content="text/html; charset=windows-1252" http-equiv="content-type"> <meta content="text/html; charset=windows-1252"
http-equiv="content-type">
<title>emptiness.html</title> <title>emptiness.html</title>
<link rel="stylesheet" type="text/css" href="../styles.css"> <link rel="stylesheet" type="text/css" href="../styles.css">
<style> <style>
u { font-weight: normal; text-decoration: none; } u { font-weight: normal; text-decoration: none; }
</style> </style>
</head> </head>
<body> <body>
<h4>Passing nothing</h4> <h4>Passing nothing</h4>
<div> <div> Although rarely desirable it has always been legal in C++ to
Although rarely desirable it has always been legal in C++ to pass nothing, aka no preprocessor tokens, pass nothing, aka no preprocessor tokens, as an argument when
as an argument when invoking a macro, whether the equivalent parameter be a regular parameter or a variadic one. invoking a macro, whether the equivalent parameter be a regular
</div> parameter or a variadic one. </div>
<div class="code"> <div class="code">
<pre> <pre> #define SOME_MACRO(Parameter1,Parameter2) macro expansion using Parameter1 and Parameter2
#define SOME_MACRO(Parameter1,Parameter2) macro expansion using Parameter1 and Parameter2
#define SOME_VARIADIC_MACRO(Parameter1,...) macro expansion using Parameter1 and __VA_ARGS__ #define SOME_VARIADIC_MACRO(Parameter1,...) macro expansion using Parameter1 and __VA_ARGS__
SOME_MACRO(a,b) // Normal SOME_MACRO(a,b) // Normal
@ -30,17 +31,17 @@
but in C++20 exactly equivalent to SOME_VARIADIC_MACRO(a,) */</pre> but in C++20 exactly equivalent to SOME_VARIADIC_MACRO(a,) */</pre>
</div> </div>
<h4>Expanding to nothing</h4> <h4>Expanding to nothing</h4>
<div> <div> Given certain arguments a macro might expand to nothing, aka
Given certain arguments a macro might expand to nothing, aka no preprocessor tokens. This may no preprocessor tokens. This may happen more than in the previous
happen more than in the previous case of an argument to a macro being nothing because the expansion of a macro case of an argument to a macro being nothing because the expansion
is often used to initialize some C++ construct, and C++ has some places where of a macro is often used to initialize some C++ construct, and C++
a part of a compile-time construct can be empty. However a macro which expands to nothing has some places where a part of a compile-time construct can be
rarely occurs when that macro's expansion is used as an argument to another macro because we would again have empty. However a macro which expands to nothing rarely occurs when
a macro where we are passing nothing as an argument. that macro's expansion is used as an argument to another macro
</div> because we would again have a macro where we are passing nothing
<div class="code"> as an argument. </div>
<pre> <div class="code">
#define ANOTHER_MACRO(Parameter1,Parameter2) /* expands to nothing when Parameter1 and Parameter2 <pre> #define ANOTHER_MACRO(Parameter1,Parameter2) /* expands to nothing when Parameter1 and Parameter2
are numbers, otherwise expands to some preprocessing are numbers, otherwise expands to some preprocessing
token, such as '1' */ token, such as '1' */
@ -50,103 +51,161 @@
SOME_MACRO(ANOTHER_MACRO(1,2),z) // Legal, first argument is empty as ANOTHER_MACRO Expands to nothing</pre> SOME_MACRO(ANOTHER_MACRO(1,2),z) // Legal, first argument is empty as ANOTHER_MACRO Expands to nothing</pre>
</div> </div>
<h4>Emptiness defined</h4> <h4>Emptiness defined</h4>
<div> <div> Passing nothing as a macro argument or a macro expanding to
Passing nothing as a macro argument or a macro expanding to nothing I term as 'emptiness', nothing I term as 'emptiness', as 'nothing' is too amorphous a
as 'nothing' is too amorphous a term which can be used in too many other contexts for my liking. term which can be used in too many other contexts for my liking.
In the vast majority of cases when designing a macro for use emptiness is not a part of such In the vast majority of cases when designing a macro for use
a design, and passing emptiness as an argument or expanding to emptiness is not anything emptiness is not a part of such a design, and passing emptiness as
that someone writing a macro takes into account when he explains to other programmers an argument or expanding to emptiness is not anything that someone
how a macro should be used.<br><br> writing a macro takes into account when he explains to other
Other than the fact that macros are generally created so that some actual preprocessor programmers how a macro should be used.<br>
data of a particular kind needs to be passed as arguments or gets generated as part of <br>
macro expansion when a macro is invoked, there is another very good reason why working Other than the fact that macros are generally created so that some
with emptiness is not part of a macro's design: there has been no perfectly fail-safe actual preprocessor data of a particular kind needs to be passed
way to test for emptiness during macro expansion, whether it be in creating macros as arguments or gets generated as part of macro expansion when a
using just the facilities of the C++ standard or using a 3rd party library, such as macro is invoked, there is another very good reason why working
this Boost preprocessor library. When I say 'fail-safe' I mean that there has always with emptiness is not part of a macro's design: there has been no
been some argument input, no matter how small the number of potential cases, where a perfectly fail-safe way to test for emptiness during macro
macro designed to test whether or not the preprocessor data passed to it as an argument expansion, whether it be in creating macros using just the
when the macro is invoked is actually empty, fails in some facilities of the C++ standard or using a 3rd party library, such
way, with the failure normally occurring as a preprocessor error.<br><br> as this Boost preprocessor library. When I say 'fail-safe' I mean
Of course this does not mean that the best macro designed to test for emptiness that there has always been some argument input, no matter how
will not work correctly the vast majority of the time. It only means that there small the number of potential cases, where a macro designed to
has been no guarantee that such a macro will work correctly all 100% of the time. test whether or not the preprocessor data passed to it as an
Nonetheless there have been uses of testing for emptiness, when a macro documents argument when the macro is invoked is actually empty fails in some
what a particular argument should generally consist of, even if the test is not way, with the failure normally occurring as a preprocessor error.<br>
guaranteed to work 100% of the time if particular unexpected argument data does get passed. <br>
</div> Of course this does not mean that the best macro designed to test
for emptiness will not work correctly the vast majority of the
time. It only means that there has been no guarantee that such a
macro will work correctly all 100% of the time. Nonetheless there
have been uses of testing for emptiness, when a macro documents
what a particular argument should generally consist of, even if
the test is not guaranteed to work 100% of the time if particular
unexpected argument data does get passed. </div>
<h4>A C++20 solution for testing for emptiness</h4> <h4>A C++20 solution for testing for emptiness</h4>
<div> <div> The C++ standard committee recognized, in the upcoming
The C++ standard committee recognized, in the upcoming specification for the C++20 standard, specification for the C++20 standard, that a way of testing
that a way of testing whether variadic data is empty or not in the expansion of a variadic whether variadic data is empty or not in the expansion of a
macro would be very useful when designing certain types of macros. Because of this variadic macro would be very useful when designing certain types
the C++20 standard added a preprocessor construct which could do this in a certain way of macros. Because of this the C++20 standard added a preprocessor
for variadic data in the expansion of a variadic macro. construct which could do this in a certain way for variadic data
The construct is called __VA_OPT__. I am not going to explain that construct here, as the in the expansion of a variadic macro. The construct is called
documentation for it is part of the upcoming C++20 standard and is readily available on __VA_OPT__, as in '__VA_OPT__ ( prepocessing tokens )' specified
various C++ sites on the Internet, but the further upshot of adding the __VA_OPT__ construct in the replacement list of a variadic macro. <br>
to C++20 is that it is now possible to create a variadic macro which is 100% reliable in <br>
testing for emptiness whenever a compiler supports the __VA_OPT__ construct in its The way that the __VA_OPT__ constructs works is that if the
compilation of preprocessor code.<br><br> variadic arguments to the variadic macro are empty or expand to
For such a macro to always work which tests for emptiness the code must know when emptiness then the __VA_OPT__ construct and its enclosed
the __VA_OPT__ construct is available. It is not enough to know that a compiler is preprocessing token data expands to nothing, or in C++ terms "a
working at the C++20 level, since as all C++ programmers know an adherence to a C++ standard single placemarker preprocessing token". Otherwise the __VA_OPT__
level never guarantees that a particular compiler supports every aspect of that level. construct expands to its enclosed preprocessing tokens. A further,
Happily there is a way to test whether a compiler supports the __VA_OPT__ construct possibly unintended, upshot of adding the __VA_OPT__ construct to
as long as the compiler supports variadic macros, and that way has been openly published C++20 is that it is now possible to create a variadic macro which
on the Internet although the actual macro code would not have been hard to create even if it had is 100% reliable in testing for emptiness whenever a compiler
not publicly appeared. This library uses that code to test for __VA_OPT__ as a necessary prelude supports the __VA_OPT__ construct in its compilation of
for creating a variadic macro which is 100% reliable in testing for emptiness.<br><br> preprocessor code.<br>
The Boost Preprocessor macro for testing whether the __VA_OPT__ construct is supported during <br>
compilation is called BOOST_PP_VARIADIC_HAS_OPT, which is a function-like macro taking no parameters For such a macro to always work which tests for emptiness the code
and returning 1 if the __VA_OPT__ construct is supported and 0 if it is not. The macro must know when the __VA_OPT__ construct is available. It is not
only returns 1 when variadic macros are supported, when the compiler is at the C++20 level, enough to know that a compiler is working at the C++20 level,
and when the __VA_OPT__ construct can be used according to the C++20 standard. In particular since as all C++ programmers know an adherence to a C++ standard
the macro needs the compiler to be working at the C++20 level despite the fact that at least level never guarantees that a particular compiler supports every
one major compiler supports the __VA_OPT__ construct in some of its latest releases even aspect of that level. Happily there is a way to test whether a
when the compiler is being used at a C++ standard level below that of C++20. The reason this compiler supports the __VA_OPT__ construct as long as the compiler
Boost preprocessor library requires the C++20 level is because that same major compiler supports variadic macros, and that way has been openly published
can produce a warning, or even an error, when it even sees a macro using the __VA_OPT__ on the Internet, although the actual macro code would not have
construct at a level below C++20, even though it supports it, if other compiler options been hard to create even if it had not publicly appeared. This
requiring strict adherence to the level of the C++ standard being used are passed on the library uses that code to test for __VA_OPT__ as a necessary
command line. So taking a conservative approach the BOOST_PP_VARIADIC_HAS_OPT macros requires prelude for creating a variadic macro which is 100% reliable in
compilation at the C++20 level, along with variadic macro support, along with the testing code testing for emptiness.<br>
expanding to 1, in order to specify that __VA_OPT__ is supported.<br><br> <br>
The actual Boost Preprocessor library for testing for emptiness in C++20 mode is called The Boost Preprocessor macro for testing whether the __VA_OPT__
BOOST_PP_CHECK_EMPTY. The macro is a variadic macro with a single variadic parameter. The construct is supported during compilation is called
macro only exists if our previous macro for testing for __VA_OPT__ called BOOST_PP_VARIADIC_HAS_OPT BOOST_PP_VARIADIC_HAS_OPT, which is a function-like macro taking
expands to 1 when invoked as BOOST_PP_VARIADIC_HAS_OPT(). If BOOST_PP_VARIADIC_HAS_OPT() expands to 0 no parameters and returning 1 if the __VA_OPT__ construct is
the BOOST_PP_CHECK_EMPTY macro does not exist at all in this library. The input to the macro supported and 0 if it is not. The macro only returns 1 when
can be any variadic data. If the data passed to the macro is empty, or if the data passed to variadic macros are supported, when the compiler is at the C++20
the macro is not empty but when the data itself is expanded it is empty, the macro returns level, and when the __VA_OPT__ construct can be used according to
1, otherwise it returns 0. The macro works 100% of the time and is completely reliable no matter what the C++20 standard. In particular the macro needs the compiler to
preprocessor data is passed to it. But of course it only works when compiling at the C++20 be working at the C++20 level despite the fact that at least one
level with the __VA_OPT__ construct supported by the compiler. It solves an old problem major compiler supports the __VA_OPT__ construct in some of its
that it has never been possible, prior to C++20, to provide a 100% reliable implementation latest releases even when the compiler is being used at a C++
of a macro which tests for emptiness in C++.<br><br> standard level below that of C++20. The reason this Boost
Eventually more C++ compilers will support C++20 and the __VA_OPT__ construct and more programmers preprocessor library requires the C++20 level is because that same
will use compilers at the C++20 level. At that point the macro BOOST_PP_CHECK_EMPTY can be major compiler can produce a warning, or even an error, when it
used reliably for testing emptiness in preprocessor data in macro code by all those programmers. even sees a macro using the __VA_OPT__ construct at a level below
This does not mean that designing macros with emptiness in mind needs to be done, much less C++20, even though it supports it, if other compiler options
considered, but that the possibility of doing so with complete reliability will be there if needed requiring strict adherence to the level of the C++ standard being
by the macro programmer. Along with the __VA_OPT__ construct as mandated by the C++20 standard used are passed on the command line. So taking a conservative
the BOOST_PP_CHECK_EMPTY adds two more tools in the arsenal of macro programming, which is a good approach the BOOST_PP_VARIADIC_HAS_OPT macros requires compilation
thing, while programmers who wanted to ignore any dealing with emptiness in macro code can continue to do so. at the C++20 level, along with variadic macro support, along with
</div> the testing code expanding to 1, in order to specify that
__VA_OPT__ is supported.<br>
<br>
The actual Boost Preprocessor library for testing for emptiness in
C++20 mode is called BOOST_PP_CHECK_EMPTY. The macro is a variadic
macro with a single variadic parameter. The macro only exists if
our previous macro for testing for __VA_OPT__, called
BOOST_PP_VARIADIC_HAS_OPT, expands to 1 when invoked as
BOOST_PP_VARIADIC_HAS_OPT(). If BOOST_PP_VARIADIC_HAS_OPT()
expands to 0 the BOOST_PP_CHECK_EMPTY macro does not exist at all
in this library. The input to the BOOST_PP_CHECK_EMPTY macro can
be any variadic data. If the data passed to the macro is empty, or
if the data passed to the macro is not empty but when the data
itself is expanded it is empty, the macro returns 1, otherwise it
returns 0. The macro works 100% of the time and is completely
reliable no matter what preprocessor data is passed to it. But of
course it only works when compiling at the C++20 level with the
__VA_OPT__ construct supported by the compiler. It solves an old
problem that it has never been possible, prior to C++20, to
provide a 100% reliable implementation of a macro which tests for
emptiness in C++.<br>
<br>
Along with the valuable BOOST_PP_CHECK_EMPTY macro the Boost
Preprocessor library has also added a more flexible, if slightly
verbose, alternative to the __VA_OPT__ construct, which works by
using the ability of BOOST_PP_CHECK_EMPTY to reliably test for
emptiness. This macro is called BOOST_PP_VA_OPT and allows the
programmer to specify preprocessing tokens for expansion both when
the variadic data is <b>not</b> empty and when the variadic data
is empty. This improves on the __VA_OPT__ construct's ability to
specify preprocessing tokens for expansion only when the variadic
data is not empty. Like BOOST_PP_CHECK_EMPTY, which it uses, the
BOOST_PP_VA_OPT macro only exists when BOOST_PP_VARIADIC_HAS_OPT()
expands to 1. You can read further about how this macro works as
an alternative to the C++20 __VA_OPT__ construct in the
documentation for the macro itself.<br>
<br>
Eventually more C++ compilers will support C++20 and the
__VA_OPT__ construct and more programmers will use compilers at
the C++20 level. At that point the macro BOOST_PP_CHECK_EMPTY can
be used reliably for testing emptiness in preprocessor data in
macro code by all those programmers. The BOOST_PP_VA_OPT macro
serves as a useful example of such use. This does not mean that
designing macros with emptiness in mind needs to be done, much
less considered, but that the possibility of doing so with
complete reliability will be there if needed by the macro
programmer. Along with the __VA_OPT__ construct as mandated by the
C++20 standard the BOOST_PP_CHECK_EMPTY and BOOST_PP_VA_OPT macros
add three more tools in the arsenal of macro programming, which is
a good thing, while programmers who wanted to ignore any dealing
with emptiness in macro code can continue to do so. </div>
<b>See</b> <b>Also</b><br> <b>See</b> <b>Also</b><br>
<ul> <ul>
<li><a href="../ref/variadic_has_opt.html">BOOST_PP_VARIADIC_HAS_OPT</a></li> <li><a href="../ref/variadic_has_opt.html">BOOST_PP_VARIADIC_HAS_OPT</a></li>
<li><a href="../ref/check_empty.html">BOOST_PP_CHECK_EMPTY</a></li> <li><a href="../ref/check_empty.html">BOOST_PP_CHECK_EMPTY</a></li>
<li><a href="../ref/va_opt.html">BOOST_PP_VA_OPT</a><br>
</li>
</ul> </ul>
<hr size="1"> <hr size="1">
<div style="margin-left: 0px;"> <i><EFBFBD> Copyright <div style="margin-left: 0px;"> <i><EFBFBD> Copyright Edward Diener 2019</i>
Edward Diener </div>
2019</i> </div> <div style="margin-left: 0px;">
<div style="margin-left: 0px;"> <p><small>Distributed under the Boost Software License, Version
<p><small>Distributed under the Boost Software License, 1.0. (See accompanying file <a
Version 1.0. href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or
(See accompanying file <a href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> copy at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</small></p>
or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</small></p>
</div> </div>
</body> </body>
</html> </html>