2021-10-05 21:37:46 +02:00

271 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Useful variadic macros not in Boost PP</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.10">
<link rel="up" href="../index.html" title="Chapter 1. The Variadic Macro Data Library 1.10">
<link rel="prev" href="vmd_identifier_subtype.html" title="Identifier subtypes">
<link rel="next" href="vmd_useful/vmd_identity.html" title="Generating emptiness and identity">
</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_identifier_subtype.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_useful/vmd_identity.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_useful"></a><a class="link" href="vmd_useful.html" title="Useful variadic macros not in Boost PP">Useful variadic macros
not in Boost PP</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert">Asserting
and data types</a></span></dt>
<dt><span class="section"><a href="vmd_useful/vmd_identity.html">Generating
emptiness and identity</a></span></dt>
<dt><span class="section"><a href="vmd_useful/vmd_empty_ppdata.html">Functionality
for "empty" seqs and tuples</a></span></dt>
</dl></div>
<p>
Previous sections of this documentation have explained how VMD can be used
to parse VMD data types, as well as recognize emptiness.
</p>
<p>
Another area of functionality of VMD involves useful variadic macros, based
on the previous functionality, which expands on similar macros already in Boost
PP. These variadic macros can be divided into sections illustrating these areas
of behavior:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Expanded assertion macros
</li>
<li class="listitem">
Expanded identity functionality
</li>
<li class="listitem">
Expanded seq and tuple functionality for "empty" seqs and tuples
</li>
</ol></div>
<p>
Sub-sections for each of these now follow in the documentation.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="variadic_macro_data.vmd_useful.vmd_assert"></a><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert" title="Asserting and data types">Asserting
and data types</a>
</h3></div></div></div>
<p>
The VMD macros for identifying data types work best when the macro logic
can take different paths depending on the type of data being passed for a
macro parameter. But occasionally the preprocessor metaprogrammer wants to
simply verify that the macro parameter data is of the correct data type,
else a preprocessing error should be generated to notify the programmer invoking
the macro that the data passed is the incorrect type.
</p>
<h5>
<a name="variadic_macro_data.vmd_useful.vmd_assert.h0"></a>
<span class="phrase"><a name="variadic_macro_data.vmd_useful.vmd_assert.using_boost_vmd_assert"></a></span><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert.using_boost_vmd_assert">Using
BOOST_VMD_ASSERT</a>
</h5>
<p>
The Boost PP library has a macro which produces a preprocessing error when
the condition passed to it is 0. This macro is called BOOST_PP_ASSERT. The
macro produces a preprocessor error by forcing a call to an internal macro
with the wrong number of arguments. According to the C++ standard this should
always cause an immediate preprocessing error for conforming compilers.
</p>
<p>
Unfortunately VC++ with its default preprocessor will only produce a warning
when the wrong number of arguments are passed to a macro. Therefore the BOOST_PP_ASSERT
macro does not produce a preprocessing error using VC++ with its default
preprocessor. Amazingly enough there appears to be no other way in which
VC++ with its default preprocessor can be forced to issue a preprocessing
error by invoking a macro ( if you find one please tell me about it ). However
one can create invalid C++ as the output from a macro invocation which causes
VC++ to produce a compiler error when the VC++ compiler later encounters
the construct.
</p>
<p>
This is what the macro BOOST_VMD_ASSERT does. It takes the same conditional
argument as BOOST_PP_ASSERT and it calls BOOST_PP_ASSERT when not used with
VC++ with its default preprocessor, otherwise if the condition is 0 it generates
a compiler error by generating invalid C++ when used with VC++ with its default
preprocessor. The compiler error is generated by producing invalid C++ whose
form is:
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="keyword">char</span> <span class="identifier">BOOST_VMD_ASSERT_ERROR</span><span class="special">[-</span><span class="number">1</span><span class="special">];</span>
</pre>
<p>
By passing a second optional argument, whose form is a preprocessing identifier,
to BOOST_VMD_ASSERT you can generate the invalid C++ for VC++ with its default
preprocessor, if the first argument is 0, of the form:
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="keyword">char</span> <span class="identifier">optional_argument</span><span class="special">[-</span><span class="number">1</span><span class="special">];</span>
</pre>
<p>
instead. This may give a little more clarity, if desired, to the C++ error
generated.
</p>
<p>
If the first conditional argument is not 0, BOOST_VMD_ASSERT produces no
output.
</p>
<h5>
<a name="variadic_macro_data.vmd_useful.vmd_assert.h1"></a>
<span class="phrase"><a name="variadic_macro_data.vmd_useful.vmd_assert.boost_vmd_assert_usage"></a></span><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert.boost_vmd_assert_usage">BOOST_VMD_ASSERT
Usage</a>
</h5>
<p>
To use the BOOST_VMD_ASSERT macro either include the general header:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</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">&gt;</span>
</pre>
<p>
or include the specific header:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
</pre>
<h5>
<a name="variadic_macro_data.vmd_useful.vmd_assert.h2"></a>
<span class="phrase"><a name="variadic_macro_data.vmd_useful.vmd_assert.assertions_for_data_types"></a></span><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert.assertions_for_data_types">Assertions
for data types </a>
</h5>
<p>
The data types have their own assertion macros. These are largely just shortcuts
for passing the result of the identifying macros to BOOST_VMD_ASSERT. These
assertion macros are:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
emptiness, BOOST_VMD_ASSERT_IS_EMPTY
</li>
<li class="listitem">
identifier, BOOST_VMD_ASSERT_IS_IDENTIFIER
</li>
<li class="listitem">
number, BOOST_VMD_ASSERT_IS_NUMBER
</li>
<li class="listitem">
array, BOOST_VMD_ASSERT_IS_ARRAY
</li>
<li class="listitem">
list, BOOST_VMD_ASSERT_IS_LIST
</li>
<li class="listitem">
seq, BOOST_VMD_ASSERT_IS_SEQ
</li>
<li class="listitem">
tuple, BOOST_VMD_ASSERT_IS_TUPLE
</li>
<li class="listitem">
type, BOOST_VMD_ASSERT_IS_TYPE
</li>
</ul></div>
<p>
Each of these macros take as parameters the exact same argument as their
corresponding identifying macros. But instead of returning non-zero or 0,
each of these macros produce a compiler error if the type of the input is
not correct.
</p>
<p>
Each of these macros only check for its assertion when the macro BOOST_VMD_ASSERT_DATA
is set to 1. By default BOOST_VMD_ASSERT_DATA is only set to 1 in compiler
debug mode. The programmer can manually set BOOST_VMD_ASSERT_DATA to 1 prior
to using one the data types assert macros if he wishes.
</p>
<h5>
<a name="variadic_macro_data.vmd_useful.vmd_assert.h3"></a>
<span class="phrase"><a name="variadic_macro_data.vmd_useful.vmd_assert.boost_vmd_assert_usage0"></a></span><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert.boost_vmd_assert_usage0">BOOST_VMD_ASSERT_...
Usage</a>
</h5>
<p>
To use the individual BOOST_VMD_ASSERT_... macros either include the general
header:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</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">&gt;</span>
</pre>
<p>
or include the specific header:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_EMPTY</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_identifier</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_IDENTIFIER</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_number</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_NUMBER</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_array</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_ARRAY</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_list</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_LIST</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_seq</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_SEQ</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_tuple</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_TUPLE</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_type</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// BOOST_VMD_ASSERT_IS_TYPE</span>
</pre>
<h5>
<a name="variadic_macro_data.vmd_useful.vmd_assert.h4"></a>
<span class="phrase"><a name="variadic_macro_data.vmd_useful.vmd_assert.assertions_and_vc"></a></span><a class="link" href="vmd_useful.html#variadic_macro_data.vmd_useful.vmd_assert.assertions_and_vc">Assertions
and VC++ </a>
</h5>
<p>
The VC++ compiler with its default preprocessor has a quirk when dealing
with BOOST_VMD_ASSERT and the data type assert macros. If you invoke one
of the assert macros within another macro which would normally generate output
preprocessor tokens, it is necessary when using VC++ with its default preprocessor
to concatenate the result of the assert macro to whatever other preprocessor
data is being generated, even if the assert macro does not generate an error.
</p>
<p>
As a simple example let us suppose we have a macro expecting a tuple and
generating 1 if the tuple has more than 2 elements, otherwise it generates
0. Ordinarily we could write:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">comparison</span><span class="special">/</span><span class="identifier">greater</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">control</span><span class="special">/</span><span class="identifier">iif</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">tuple</span><span class="special">/</span><span class="identifier">size</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_tuple</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#define</span> <span class="identifier">AMACRO</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">BOOST_VMD_ASSERT_IS_TUPLE</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_IIF</span><span class="special">(</span><span class="identifier">BOOST_PP_GREATER</span><span class="special">(</span><span class="identifier">BOOST_PP_TUPLE_SIZE</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">),</span> <span class="number">2</span><span class="special">),</span><span class="number">1</span><span class="special">,</span><span class="number">0</span><span class="special">)</span>
</pre>
<p>
but for VC++ with its default preprocessor we must write
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">cat</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">comparison</span><span class="special">/</span><span class="identifier">greater</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">control</span><span class="special">/</span><span class="identifier">iif</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">tuple</span><span class="special">/</span><span class="identifier">size</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">vmd</span><span class="special">/</span><span class="identifier">assert_is_tuple</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#define</span> <span class="identifier">AMACRO</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_CAT</span> <span class="special">\</span>
<span class="special">(</span> <span class="special">\</span>
<span class="identifier">BOOST_VMD_ASSERT_IS_TUPLE</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">),</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_IIF</span><span class="special">(</span><span class="identifier">BOOST_PP_GREATER</span><span class="special">(</span><span class="identifier">BOOST_PP_TUPLE_SIZE</span><span class="special">(</span><span class="identifier">atuple</span><span class="special">),</span> <span class="number">2</span><span class="special">),</span><span class="number">1</span><span class="special">,</span><span class="number">0</span><span class="special">)</span> <span class="special">\</span>
<span class="special">)</span>
</pre>
<p>
VC++ with its default preprocessor does not work correctly in the first instance,
erroneously getting confused as far as compiler output is concerned. But
by using BOOST_PP_CAT in the second condition VC++ with its default preprocessor
will work correctly with VMD assertions.
</p>
</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_identifier_subtype.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_useful/vmd_identity.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>