123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
- <title>Specific macros for working with data types</title>
- <link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
- <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
- <link rel="home" href="../index.html" title="Chapter 1. The Variadic Macro Data Library 1.9">
- <link rel="up" href="../index.html" title="Chapter 1. The Variadic Macro Data Library 1.9">
- <link rel="prev" href="vmd_data_types.html" title="Data types">
- <link rel="next" href="vmd_specific/vmd_constraints.html" title="Macro constraints">
- </head>
- <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
- <table cellpadding="2" width="100%"><tr>
- <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
- <td align="center"><a href="../../../../../index.html">Home</a></td>
- <td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
- <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
- <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
- <td align="center"><a href="../../../../../more/index.htm">More</a></td>
- </tr></table>
- <hr>
- <div class="spirit-nav">
- <a accesskey="p" href="vmd_data_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="vmd_specific/vmd_constraints.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="variadic_macro_data.vmd_specific"></a><a class="link" href="vmd_specific.html" title="Specific macros for working with data types">Specific macros for working
- with data types</a>
- </h2></div></div></div>
- <div class="toc"><dl class="toc">
- <dt><span class="section"><a href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty">Emptiness</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_constraints.html">Macro
- constraints</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_identifier.html">Identifiers</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_number.html">Numbers</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_type.html">Types</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_pp_data_types.html">VMD
- and Boost PP data types</a></span></dt>
- <dt><span class="section"><a href="vmd_specific/vmd_identifying.html">Identifying
- data types</a></span></dt>
- </dl></div>
- <p>
- VMD has a number of specific macros for parsing data types. Each of these macros
- asks if some input is a particular VMD data type.
- </p>
- <div class="section">
- <div class="titlepage"><div><div><h3 class="title">
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty"></a><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty" title="Emptiness">Emptiness</a>
- </h3></div></div></div>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h0"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.passing_empty_arguments"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.passing_empty_arguments">Passing
- empty arguments</a>
- </h5>
- <p>
- It is possible to pass an empty argument to a macro. The official terminology
- for this in the C++ standard is an argument "consisting of no preprocessing
- tokens".
- </p>
- <p>
- Let us consider a number of cases without worrying too much what the macro
- output represents.
- </p>
- <p>
- Consider these two function-like macros:
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">SMACRO</span><span class="special">()</span> <span class="identifier">someoutput</span>
- <span class="preprocessor">#define</span> <span class="identifier">EMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="identifier">otheroutput</span> <span class="identifier">x</span>
- </pre>
- <p>
- The first macro takes no parameters so invoking it must always be done by
- </p>
- <pre class="programlisting"><span class="identifier">SMACRO</span><span class="special">()</span>
- </pre>
- <p>
- and passing any arguments to it would be invalid.
- </p>
- <p>
- The second macro takes a single parameter. it can be evoked as
- </p>
- <pre class="programlisting"><span class="identifier">EMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">)</span>
- </pre>
- <p>
- but it also can be invoked as
- </p>
- <pre class="programlisting"><span class="identifier">EMACRO</span><span class="special">()</span>
- </pre>
- <p>
- In the second invocation of EMACRO we are passing an empty argument to the
- macro. Similarly for any macro having 1 or more parameters, an empty argument
- can be validly passed for any of the parameters, as in
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">MMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">,</span><span class="identifier">z</span><span class="special">)</span> <span class="identifier">x</span> <span class="identifier">y</span> <span class="identifier">z</span>
- <span class="identifier">MMACRO</span><span class="special">(</span><span class="number">1</span><span class="special">,,</span><span class="number">2</span><span class="special">)</span>
- </pre>
- <p>
- An empty argument is an argument even if we are passing nothing.
- </p>
- <p>
- Because an empty argument can be passed for a given parameter of a macro
- does not mean one should do so. Any given macro will specify what each argument
- to a macro should represent, and it is has normally been very rare to encounter
- a macro which specifies that an empty argument can logically be passed for
- a given argument. But from the perspective of standard C++ it is perfectly
- valid to pass an empty argument for a macro parameter.
- </p>
- <p>
- The notion of passing empty arguments can be extended to passing empty data
- which "consists of no preprocessing tokens" in slightly more complicated
- situations. It is possible to pass empty data as an argument to a variadic
- macro in the form of variadic macro data, as in
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">VMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,...)</span> <span class="identifier">x</span> <span class="identifier">__VA_ARGS__</span>
- </pre>
- <p>
- invoked as
- </p>
- <pre class="programlisting"><span class="identifier">VMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">,)</span>
- </pre>
- <p>
- Here one passes empty data as the variadic macro data and it is perfectly
- valid C++. Please notice that this different from
- </p>
- <pre class="programlisting"><span class="identifier">VMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">)</span>
- </pre>
- <p>
- which is not valid C++, prior to C++20, since something must be passed for
- the variadic argument. In C++20 the above invocation is valid and is exactly
- the same as in our previous example of 'VMACRO(somedata,)' where one passes
- empty data as the variadic macro data. Similarly one could invoke the macro
- as
- </p>
- <pre class="programlisting"><span class="identifier">VMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">,</span><span class="identifier">vdata1</span><span class="special">,,</span><span class="identifier">vdata3</span><span class="special">)</span>
- </pre>
- <p>
- where one is passing variadic macro data but an element in the variadic macro
- data is empty.
- </p>
- <p>
- Furthermore if we are invoking a macro which expects a Boost PP data type,
- such as a tuple, we could also validly pass empty data for all or part of
- the data in a tuple, as in
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">TMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">atuple</span><span class="special">)</span> <span class="identifier">x</span> <span class="identifier">atuple</span>
- <span class="identifier">TMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">,())</span>
- </pre>
- <p>
- In this case we are passing a 1 element tuple where the single element itself
- is empty.
- </p>
- <p>
- or
- </p>
- <pre class="programlisting"><span class="identifier">TMACRO</span><span class="special">(</span><span class="identifier">somedata</span><span class="special">,(</span><span class="identifier">telem1</span><span class="special">,,</span><span class="identifier">telem2</span><span class="special">,</span><span class="identifier">teleem3</span><span class="special">))</span>
- </pre>
- <p>
- In this case we are passing a 4 element tuple where the second element is
- empty.
- </p>
- <p>
- Again either invocation is valid C++ but it is not necessarily what the designed
- of the macro has desired, even if in both cases the macro designer has specified
- that the second parameter must be a tuple for the macro to work properly.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h1"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.returning_emptiness"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.returning_emptiness">Returning
- emptiness</a>
- </h5>
- <p>
- Similar to passing empty arguments in various ways to a macro, the data which
- a macro returns ( or 'generates' may be a better term ) could be empty, in
- various ways. Again I am not necessarily promoting this idea as a common
- occurrence of macro design but merely pointing it out as valid C++ preprocessing.
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">RMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">,</span><span class="identifier">z</span><span class="special">)</span>
- <span class="identifier">RMACRO</span><span class="special">(</span><span class="identifier">data1</span><span class="special">,</span><span class="identifier">data2</span><span class="special">,</span><span class="identifier">data3</span><span class="special">)</span>
- </pre>
- <p>
- It is perfectly valid C++ to return "nothing" from a macro invocation.
- In fact a number of macros in Boost PP do that based on the preprocessor
- metaprogramming logic of the macro, and are documented as such.
- </p>
- <p>
- Similarly one could return nothing as part or all of a Boost PP data type
- or even as part of variadic macro data.
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">TRETMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">,</span><span class="identifier">z</span><span class="special">)</span> <span class="special">()</span>
- <span class="preprocessor">#define</span> <span class="identifier">TRETMACRO1</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">,</span><span class="identifier">z</span><span class="special">)</span> <span class="special">(</span><span class="identifier">x</span><span class="special">,,</span><span class="identifier">y</span><span class="special">,,</span><span class="identifier">z</span><span class="special">)</span>
- <span class="preprocessor">#define</span> <span class="identifier">VRETMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">,</span><span class="identifier">z</span><span class="special">)</span> <span class="identifier">x</span><span class="special">,,</span><span class="identifier">y</span><span class="special">,,</span><span class="identifier">z</span>
- </pre>
- <p>
- Here again we are returning something but in terms of a Boost PP tuple or
- in terms of variadic data, we have elements which are empty.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h2"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.emptiness_in_preprocessor_metapr"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.emptiness_in_preprocessor_metapr">Emptiness
- in preprocessor metaprogramming</a>
- </h5>
- <p>
- In the examples given above where "emptiness" in one form of another
- is passed as arguments to a macro or returned from a macro, the examples
- I have given were created as simplified as possible to illustrate my points.
- In actual preprocessor metaprogramming, using Boost PP, where complicated
- logic is used to generate macro output based on the arguments to a macro,
- it might be useful to allow and work with empty data if one were able to
- test for the fact that data was indeed empty.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h3"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.testing_for_empty_data"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.testing_for_empty_data">Testing
- for empty data</a>
- </h5>
- <p>
- Currently Boost PP has an undocumented macro for testing whether a parameter
- is empty of not, written without the use of variadic macros. The macro is
- called BOOST_PP_IS_EMPTY. The macro is by its nature flawed, since there
- is no generalized way of determining whether or not a parameter is empty
- using the C++ preprocessor prior to C++20. But the macro will work given
- input limited in various ways or if the input is actually empty.
- </p>
- <p>
- Paul Mensonides, the developer of Boost PP and the BOOST_PP_IS_EMPTY macro
- in that library, also wrote a better macro using variadic macros, for determining
- whether or not a parameter is empty or not, which he published on the Internet
- in response to a discussion about emptiness. This macro is also not perfect,
- since there is no perfect solution prior to C++20, but will work correctly
- with almost all input. I have adapted his code for VMD and developed my own
- very slightly different code.
- </p>
- <p>
- The macro is called <code class="computeroutput"><a class="link" href="../BOOST_VMD_IS_EMPTY.html" title="Macro BOOST_VMD_IS_EMPTY">BOOST_VMD_IS_EMPTY</a></code>
- and will return 1 if its input is empty or 0 if its input is not empty. The
- macro is a variadic macro which make take any input <a href="#ftn.variadic_macro_data.vmd_specific.vmd_test_empty.f0" class="footnote" name="variadic_macro_data.vmd_specific.vmd_test_empty.f0"><sup class="footnote">[1]</sup></a>.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h4"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_with_a_standard_c_com"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_with_a_standard_c_com">Macro
- Flaw with a standard C++ compiler</a>
- </h5>
- <p>
- The one situation prior to C++20 where the macro does not work properly is
- if its input resolves to a function-like macro name or a sequence of preprocessor
- tokens ending with a function-like macro name and the function-like macro
- takes two or more parameters.
- </p>
- <p>
- Here is a simple example:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">is_empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">)</span> <span class="identifier">any_output</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">FMACRO</span><span class="special">)</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">some_input</span> <span class="identifier">FMACRO</span><span class="special">)</span>
- </pre>
- <p>
- In the first case the name of a function-like macro is being passed to BOOST_VMD_IS_EMPTY
- while in the second case a sequence of preprocessing tokens is being passed
- to BOOST_VMD_IS_EMPTY ending with the name of a function-like macro. The
- function-like macro also has two ( or more ) parameters. In both the cases
- above a compiler error will result from the use of BOOST_VMD_IS_EMPTY.
- </p>
- <p>
- Please note that these two problematical cases are not the same as passing
- an invocation of a function-like macro name to BOOST_VMD_IS_EMPTY, as in
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">is_empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">FMACRO</span><span class="special">(</span><span class="identifier">arg1</span><span class="special">,</span><span class="identifier">arg2</span><span class="special">))</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">someinput</span> <span class="identifier">FMACRO</span><span class="special">(</span><span class="identifier">arg1</span><span class="special">,</span><span class="identifier">arg2</span><span class="special">))</span>
- </pre>
- <p>
- which always works correctly, unless of course a particular function-like
- macro invocation resolves to either of our two previous situations.
- </p>
- <p>
- Another situation where the macro may not work properly is if the previously
- mentioned function-like macro takes a single parameter but creates an error
- when the argument passed is empty. An example of this would be:
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">FMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(+,</span><span class="identifier">x</span> <span class="identifier">C</span><span class="special">);</span>
- </pre>
- <p>
- When nothing is passed to FMACRO undefined behavior will occur since attempting
- to concatenate '+' to ' C' is UB in C++ preprocessor terms.
- </p>
- <p>
- So for a standard conforming compiler, prior to C++20, we have essentially
- two corner cases where the BOOST_VMD_IS_EMPTY does not work and, when it
- does not work it, produces a compiler error rather than an incorrect result.
- Essentially what is desired for maximum safety is that we never pass input
- ending with the name of a function-like macro name when testing for emptiness.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h5"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_with_visual_c"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_with_visual_c">Macro
- Flaw with Visual C++</a>
- </h5>
- <p>
- The VC++ preprocessor is not a standard C++ conforming preprocessor in at
- least two relevant situations to our discussion of emptiness. These situations
- combine to create a single corner case which causes the BOOST_VMD_IS_EMPTY
- macro to not work properly using VC++ when the input resolves to a function-like
- macro name.
- </p>
- <p>
- The first situation, related to our discussion of emptiness, where the VC++
- preprocessor is not a standard C++ conforming preprocessor is that if a macro
- taking 'n' number of parameters is invoked with 0 to 'n-1' parameters, the
- compiler does not give an error, but only a warning.
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">FMACRO</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">)</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span>
- <span class="identifier">FMACRO</span><span class="special">(</span><span class="number">1</span><span class="special">)</span>
- </pre>
- <p>
- should give a compiler error, as it does when using a C++ standard-conforming
- compiler, but when invoked using VC++ it only gives a warning and VC++ continues
- macro substitution with 'y' as a placemarker preprocessing token. This non-standard
- conforming action actually eliminates the case where BOOST_VMD_IS_EMPTY does
- not work properly with a standard C++ conforming compiler. But of course
- it has the potential of producing incorrect output in other macro processing
- situations unrelated to the BOOST_VMD_IS_EMPTY invocation, where a compiler
- error should occur.
- </p>
- <p>
- A second general situation, related to our discussion of emptiness, where
- the VC++ preprocessor is not a standard C++ conforming preprocessor is that
- the expansion of a macro works incorrectly when the expanded macro is a function-like
- macro name followed by a function-like macro invocation, in which case the
- macro re-expansion is erroneously done more than once. This latter case can
- be seen by this example:
- </p>
- <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">FMACRO1</span><span class="special">(</span><span class="identifier">parameter</span><span class="special">)</span> <span class="identifier">FMACRO3</span> <span class="identifier">parameter</span><span class="special">()</span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO2</span><span class="special">()</span> <span class="special">()</span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO3</span><span class="special">()</span> <span class="number">1</span>
- <span class="identifier">FMACRO1</span><span class="special">(</span><span class="identifier">FMACRO2</span><span class="special">)</span>
- <span class="identifier">should</span> <span class="identifier">expand</span> <span class="identifier">to</span><span class="special">:</span>
- <span class="identifier">FMACRO3</span><span class="special">()</span>
- <span class="identifier">but</span> <span class="identifier">in</span> <span class="identifier">VC</span><span class="special">++</span> <span class="identifier">it</span> <span class="identifier">expands</span> <span class="identifier">to</span><span class="special">:</span>
- <span class="number">1</span>
- </pre>
- <p>
- where after initially expanding the macro to:
- </p>
- <pre class="programlisting"><span class="identifier">FMACRO3</span> <span class="identifier">FMACRO2</span><span class="special">()</span>
- </pre>
- <p>
- VC++ erroneously rescans the sequence of preprocessing tokens more than once
- rather than rescan just one more time for more macro names.
- </p>
- <p>
- What these two particular preprocessor flaws in the VC++ compiler mean is
- that although BOOST_VMD_IS_EMPTY does not fail with a compiler error in the
- same case as with a standard C++ conforming compiler given previously, it
- fails by giving the wrong result in another situation.
- </p>
- <p>
- The failing situation is:
- </p>
- <p>
- when the input to BOOST_VMD_IS_EMPTY resolves to only a function-like macro
- name, and the function-like macro, when passed a single empty argument, expands
- to a Boost PP tuple, BOOST_VMD_IS_EMPTY will erroneously return 1 when using
- the Visual C++ compiler rather than either give a preprocessing error or
- return 0.
- </p>
- <p>
- Here is an example of the failure:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">is_empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO4</span><span class="special">()</span> <span class="special">(</span> <span class="identifier">any_number_of_tuple_elements</span> <span class="special">)</span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO5</span><span class="special">(</span><span class="identifier">param</span><span class="special">)</span> <span class="special">(</span> <span class="identifier">any_number_of_tuple_elements</span> <span class="special">)</span>
- <span class="preprocessor">#define</span> <span class="identifier">FMACRO6</span><span class="special">(</span><span class="identifier">param1</span><span class="special">,</span><span class="identifier">param2</span><span class="special">)</span> <span class="special">(</span> <span class="identifier">any_number_of_tuple_elements</span> <span class="special">)</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">FMACRO4</span><span class="special">)</span> <span class="comment">// erroneously returns 1, instead of 0</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">FMACRO5</span><span class="special">)</span> <span class="comment">// erroneously returns 1, instead of 0</span>
- <span class="identifier">BOOST_VMD_IS_EMPTY</span><span class="special">(</span><span class="identifier">FMACRO6</span><span class="special">)</span> <span class="comment">// erroneously returns 1, instead of generating a preprocessing error</span>
- </pre>
- <p>
- As with a standard C++ conforming compiler prior to C++20, we have a rare
- corner case where the BOOST_VMD_IS_EMPTY will not work properly, but unfortunately
- in this very similar but even rarer corner case with VC++, we will silently
- get an incorrect result rather than a compiler error.
- </p>
- <p>
- I want to reiterate that for all compilers prior to C++20 there is no perfect
- solution in C++ to the detection of emptiness even for a C++ compiler whose
- preprocessor is completely conformant, which VC++ obviously is not.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h6"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.testing_emptiness_in_c_20_mode"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.testing_emptiness_in_c_20_mode">Testing
- emptiness in C++20 mode</a>
- </h5>
- <p>
- A few compilers can currently operate in C++20 mode, by which I mean that
- you can pass a compiler flag when compiling with such a compiler which enforces
- the upcoming C++20 standard. One of the features of the C++20 standard is
- the addition of a preprocessor construct called __VA_OPT__. Because of the
- specification of how the __VA_OPT__ construct works in C++20, it is now possible
- to have the BOOST_VMD_IS_EMPTY macro work perfectly to test for emptiness
- without any of the flaws that exist in the macro for levels of the C++ standard
- before C++20. But the macro will only do a 100% reliable test for emptiness
- when the compiler is compiling in C++20 mode. For all levels of the C++ standard
- before C++20, such as C++98, C++03, C++11, C++14, and C++17, the testing
- for emptiness has the corner cases which prevent it from wroking perfectly
- which have already been discussed.
- </p>
- <p>
- Furthermore in C++20 mode it is possible that a compiler still does not yet
- support the __VA_OPT__ construct, even though it is part of the C++20 standard.
- Luckily it is possible to test whether or not a compiler supports the __VA_OPT__
- construct in C++20 mode, and the macro implementation of BOOST_VMD_IS_EMPTY
- does that before using the construct to provide a perfectly reliable implementation
- for testing emptiness.
- </p>
- <p>
- The result of all this is that when a compiler is compiling source using
- the C++20 standard, and supports the C++20 __VA_OPT__ preprocessor construct,
- the implementation provides a completely reliable way of testing for emptiness
- using the BOOST_VMD_IS_EMPTY macro. Otherwise the BOOST_VMD_IS_EMPTY macro
- has the corner cases previously discussed which make the macro less than
- 100% reliable in testing for emptiness. The good news of course is that more
- compilers will be implementaing the C++20 standard and more C++ programmers
- will be using the C++20 standard to compile their code.
- </p>
- <p>
- The programmer may know whether the compiler is being used in C++20 mode
- from the command line parameters he passes to the compiler, and the programmer
- may know whether the compiler in C++20 mode supports the __VA_OPT__ construct
- of C++20 from the compiler's documentation. But from the preprocessor programming
- perspective it would be good to find out using a macro whether or not C++20
- mode with the __VA_OPT__ construct is being used so that the BOOST_VMD_IS_EMPTY
- macro can be considered completely reliable in testing for emptiness. Such
- a macro does already exist in the Boost Preprocessor library, and it is called
- BOOST_PP_VARIADIC_HAS_OPT. You can read the documentation for this macro
- in the Boost Preprocessor library documentation, but I will give a quick
- rundown of how this works here. The macro is a function-like macro taking
- no parameters and returns 1 if the compiler is in C++20 mode and __VA_OPT__
- is supported, otherwise returns 0. The header file needed to invoke the macro
- as BOOST_PP_VARIADIC_HAS_OPT() is included as:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">variadic</span><span class="special">/</span><span class="identifier">has_opt</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- </pre>
- <p>
- The programmer does not have to be compiling in C++20 mode to invoke the
- BOOST_PP_VARIADIC_HAS_OPT macro. When the programmer is not in C++20 mode
- invoking the macro always returns 0. When the programmer is in C++20 mode
- invoking the macro returns 1 when the __VA_OPT__ construct is supported and
- returns 0 when the __VA_OPT__ construct is not supported. It does this latter
- step through clever preprocessor programming.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h7"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_conclusion"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.macro_flaw_conclusion">Macro
- Flaw conclusion</a>
- </h5>
- <p>
- With all of the above mentioned, the cases where BOOST_VMD_IS_EMPTY will
- work incorrectly are very small, even with the erroneous VC++ preprocessor,
- and I consider the macro worthwhile to use since it works correctly with
- the vast majority of possible preprocessor input, and always works correctly
- in C++20 mode with __VA_OPT__ preprocessor support.
- </p>
- <p>
- The case where it will not work, with both a C++ standard conforming preprocessor
- or with Visual C++, occurs when the name of a function-like macro is part
- of the input to BOOST_VMD_IS_EMPTY. Obviously the macro should be used by
- the preprocessor metaprogrammer when the possible input to it is constrained
- to eliminate the erroneous case.
- </p>
- <p>
- Furthermore, since emptiness can correctly be tested for in nearly every
- situation, the BOOST_VMD_IS_EMPTY macro can be used internally when the preprocessor
- metaprogrammer wants to return data from a macro and all or part of that
- data could be empty.
- </p>
- <p>
- Therefore I believe the BOOST_VMD_IS_EMPTY macro is quite useful, despite
- the corner case flaws which makes it imperfect. Consequently I believe that
- the preprocessor metaprogrammer can use the concept of empty preprocessor
- data in the design of his own macros.
- </p>
- <h5>
- <a name="variadic_macro_data.vmd_specific.vmd_test_empty.h8"></a>
- <span class="phrase"><a name="variadic_macro_data.vmd_specific.vmd_test_empty.using_the_macro"></a></span><a class="link" href="vmd_specific.html#variadic_macro_data.vmd_specific.vmd_test_empty.using_the_macro">Using
- the macro</a>
- </h5>
- <p>
- The macro BOOST_VMD_IS_EMPTY is used internally throughout VMD and macro
- programmers may find this macro useful in their own programming efforts despite
- the slight flaw in the way that it works in pre C++20 mode.
- </p>
- <p>
- You can use the general header file:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- </pre>
- <p>
- or you can use the individual header file:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">is_empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- </pre>
- <p>
- for the BOOST_VMD_IS_EMPTY macro.
- </p>
- </div>
- <div class="footnotes">
- <br><hr style="width:100; text-align:left;margin-left: 0">
- <div id="ftn.variadic_macro_data.vmd_specific.vmd_test_empty.f0" class="footnote"><p><a href="#variadic_macro_data.vmd_specific.vmd_test_empty.f0" class="para"><sup class="para">[1] </sup></a>
- For VC++ 8 the input is not variadic data but a single parameter
- </p></div>
- </div>
- </div>
- <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
- <td align="left"></td>
- <td align="right"><div class="copyright-footer">Copyright © 2010-2017 Tropic Software
- East Inc</div></td>
- </tr></table>
- <hr>
- <div class="spirit-nav">
- <a accesskey="p" href="vmd_data_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="vmd_specific/vmd_constraints.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
- </div>
- </body>
- </html>
|