boost/doc/html/boost_pfr/tutorial.html
2021-10-05 21:37:46 +02:00

525 lines
38 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.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tutorial</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="The Boost C++ Libraries BoostBook Documentation Subset">
<link rel="up" href="../boost_pfr.html" title="Chapter 28. Boost.PFR 2.0">
<link rel="prev" href="short_examples_for_the_impatient.html" title="Short Examples for the Impatient">
<link rel="next" href="limitations_and_configuration.html" title="Limitations and Configuration">
</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="short_examples_for_the_impatient.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../boost_pfr.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="limitations_and_configuration.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="boost_pfr.tutorial"></a><a class="link" href="tutorial.html" title="Tutorial">Tutorial</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="tutorial.html#boost_pfr.tutorial.why_tuples_are_bad_and_aggregate">Why
tuples are bad and aggregates are more preferable?</a></span></dt>
<dt><span class="section"><a href="tutorial.html#boost_pfr.tutorial.accessing_structure_member_by_in">Accessing
structure member by index</a></span></dt>
<dt><span class="section"><a href="tutorial.html#boost_pfr.tutorial.custom_printing_of_aggregates">Custom
printing of aggregates</a></span></dt>
<dt><span class="section"><a href="tutorial.html#boost_pfr.tutorial.three_ways_of_getting_operators">Three
ways of getting operators </a></span></dt>
<dt><span class="section"><a href="tutorial.html#boost_pfr.tutorial.reflection_of_unions">Reflection of
unions </a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_pfr.tutorial.why_tuples_are_bad_and_aggregate"></a><a class="link" href="tutorial.html#boost_pfr.tutorial.why_tuples_are_bad_and_aggregate" title="Why tuples are bad and aggregates are more preferable?">Why
tuples are bad and aggregates are more preferable?</a>
</h3></div></div></div>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span></code>
are good for generic programming, however they have disadvantages. First
of all, code that uses them becomes barely readable. Consider two definitions:
</p>
<div class="informaltable">
<a name="boost_pfr.tutorial.why_tuples_are_bad_and_aggregate.tuples_vs_aggregates"></a><table class="table">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Tuple
</p>
</th>
<th>
<p>
Aggregate
</p>
</th>
</tr></thead>
<tbody><tr>
<td>
<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"><span class="keyword">using</span> <span class="identifier">auth_info_tuple</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">int64_t</span><span class="special">,</span> <span class="comment">// What does this integer represents?</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">int64_t</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">time_t</span>
<span class="special">&gt;;</span>
</pre>
</td>
<td>
<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"><span class="keyword">struct</span> <span class="identifier">auth_info_aggregate</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">int64_t</span> <span class="identifier">user_id</span><span class="special">;</span> <span class="comment">// Oh, now I see!</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">int64_t</span> <span class="identifier">session_id</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">time_t</span> <span class="identifier">valid_till</span><span class="special">;</span>
<span class="special">};</span>
</pre>
</td>
</tr></tbody>
</table>
</div>
<p>
Definition via aggregate initializable structure is much more clear. Same
story with usages: <code class="computeroutput"><span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;(</span><span class="identifier">value</span><span class="special">);</span></code> vs. <code class="computeroutput"><span class="keyword">return</span>
<span class="identifier">value</span><span class="special">.</span><span class="identifier">session_id</span><span class="special">;</span></code>.
</p>
<p>
Another advantage of aggregates is a more efficient copy, move construction
and assignments.
</p>
<p>
Because of the above issues some guidelines recommend to <span class="bold"><strong>use
aggregates instead of tuples</strong></span>. However aggregates fail when it
comes to the functional like programming.
</p>
<p>
Boost.PFR library <span class="bold"><strong>provides tuple like methods for aggregate
initializable structures</strong></span>, making aggregates usable in contexts
where only tuples were useful.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_pfr.tutorial.accessing_structure_member_by_in"></a><a class="link" href="tutorial.html#boost_pfr.tutorial.accessing_structure_member_by_in" title="Accessing structure member by index">Accessing
structure member by index</a>
</h3></div></div></div>
<p>
The following example shows how to access structure fields by index using
<code class="computeroutput"><a class="link" href="../boost/pfr/get.html" title="Function get">boost::pfr::get</a></code>.
</p>
<p>
Let's define some structure:
</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">pfr</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">foo</span> <span class="special">{</span> <span class="comment">// defining structure</span>
<span class="keyword">int</span> <span class="identifier">some_integer</span><span class="special">;</span>
<span class="keyword">char</span> <span class="identifier">c</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
We can access fields of that structure by index:
</p>
<pre class="programlisting"><span class="identifier">foo</span> <span class="identifier">f</span> <span class="special">{</span><span class="number">777</span><span class="special">,</span> <span class="char">'!'</span><span class="special">};</span>
<span class="keyword">auto</span><span class="special">&amp;</span> <span class="identifier">r1</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;(</span><span class="identifier">f</span><span class="special">);</span> <span class="comment">// accessing field with index 0, returns reference to `foo::some_integer`</span>
<span class="keyword">auto</span><span class="special">&amp;</span> <span class="identifier">r2</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;(</span><span class="identifier">f</span><span class="special">);</span> <span class="comment">// accessing field with index 1, returns reference to `foo::c`</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_pfr.tutorial.custom_printing_of_aggregates"></a><a class="link" href="tutorial.html#boost_pfr.tutorial.custom_printing_of_aggregates" title="Custom printing of aggregates">Custom
printing of aggregates</a>
</h3></div></div></div>
<p>
The following example shows how to write your own io-manipulator for printing:
</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">pfr</span><span class="special">/</span><span class="identifier">ops</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">ostream</span><span class="special">&gt;</span>
<span class="keyword">namespace</span> <span class="identifier">my_ns</span> <span class="special">{</span>
<span class="comment">/// Usage:</span>
<span class="comment">/// struct foo {std::uint8_t a, b;};</span>
<span class="comment">/// ...</span>
<span class="comment">/// std::cout &lt;&lt; my_ns::my_io(foo{42, 22});</span>
<span class="comment">///</span>
<span class="comment">/// Output: 42, 22</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">auto</span> <span class="identifier">my_io</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">namespace</span> <span class="identifier">detail</span> <span class="special">{</span>
<span class="comment">// Helpers to print individual values</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">print_each</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">out</span> <span class="special">&lt;&lt;</span> <span class="identifier">v</span><span class="special">;</span> <span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">print_each</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">uint8_t</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">out</span> <span class="special">&lt;&lt;</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">unsigned</span><span class="special">&gt;(</span><span class="identifier">v</span><span class="special">);</span> <span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">print_each</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">int8_t</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">out</span> <span class="special">&lt;&lt;</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">v</span><span class="special">);</span> <span class="special">}</span>
<span class="comment">// Structure to keep a reference to value, that will be ostreamed lower</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">io_reference</span> <span class="special">{</span>
<span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">value</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// Output each field of io_reference::value</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">&lt;&lt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">,</span> <span class="identifier">io_reference</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&amp;&amp;</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">sep</span> <span class="special">=</span> <span class="string">""</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">for_each_field</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span> <span class="special">[&amp;](</span><span class="keyword">const</span> <span class="keyword">auto</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">out</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exchange</span><span class="special">(</span><span class="identifier">sep</span><span class="special">,</span> <span class="string">", "</span><span class="special">);</span>
<span class="identifier">detail</span><span class="special">::</span><span class="identifier">print_each</span><span class="special">(</span><span class="identifier">out</span><span class="special">,</span> <span class="identifier">v</span><span class="special">);</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">out</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="comment">// Definition:</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">auto</span> <span class="identifier">my_io</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">value</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">io_reference</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;{</span><span class="identifier">value</span><span class="special">};</span>
<span class="special">}</span>
<span class="special">}</span> <span class="comment">// namespace my_ns</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_pfr.tutorial.three_ways_of_getting_operators"></a><a class="link" href="tutorial.html#boost_pfr.tutorial.three_ways_of_getting_operators" title="Three ways of getting operators">Three
ways of getting operators </a>
</h3></div></div></div>
<p>
There are three ways to start using Boost.PFR hashing, comparison and streaming
for type <code class="computeroutput"><span class="identifier">T</span></code> in your code.
Each method has its own drawbacks and suits own cases.
</p>
<div class="table">
<a name="boost_pfr.tutorial.three_ways_of_getting_operators.ops_comp"></a><p class="title"><b>Table 28.1. Different approaches for operators</b></p>
<div class="table-contents"><table class="table" summary="Different approaches for operators">
<colgroup>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Approach
</p>
</th>
<th>
<p>
When to use
</p>
</th>
<th>
<p>
Operators could be found by ADL
</p>
</th>
<th>
<p>
Works for local types
</p>
</th>
<th>
<p>
Usable locally, without affecting code from other scopes
</p>
</th>
<th>
<p>
Ignores implicit conversion operators
</p>
</th>
<th>
<p>
Respects user defined operators
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../reference_section.html#header.boost.pfr.ops_hpp" title="Header &lt;boost/pfr/ops.hpp&gt;">boost/pfr/ops.hpp: eq, ne,
gt, lt, le, ge</a></code>
</p>
<p>
<code class="computeroutput"><a class="link" href="../reference_section.html#header.boost.pfr.io_hpp" title="Header &lt;boost/pfr/io.hpp&gt;">boost/pfr/io.hpp: io</a></code>
</p>
</td>
<td>
<p>
Use when you need to compare values by provided for them operators
or via field-by-field comparison.
</p>
</td>
<td>
<p>
no
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
no
</p>
</td>
<td>
<p>
yes
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../BOOST_PFR_FUNCTIONS_FOR.html" title="Macro BOOST_PFR_FUNCTIONS_FOR">BOOST_PFR_FUNCTIONS_FOR(T)</a></code>
</p>
</td>
<td>
<p>
Use near the type definition to define the whole set of operators
for your type.
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
no
</p>
</td>
<td>
<p>
no
</p>
</td>
<td>
<p>
yes for T
</p>
</td>
<td>
<p>
no (compile time error)
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../reference_section.html#header.boost.pfr.ops_fields_hpp" title="Header &lt;boost/pfr/ops_fields.hpp&gt;">boost/pfr/ops_fields.hpp:
eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields</a></code>
</p>
<p>
<code class="computeroutput"><a class="link" href="../reference_section.html#header.boost.pfr.io_hpp" title="Header &lt;boost/pfr/io.hpp&gt;">boost/pfr/io_fields.hpp: io_fields</a></code>
</p>
</td>
<td>
<p>
Use to implement the required set of operators for your type.
</p>
</td>
<td>
<p>
no
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
yes
</p>
</td>
<td>
<p>
yes
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><p>
More detailed description follows:
</p>
<p>
<span class="bold"><strong>1. <code class="computeroutput"><span class="identifier">eq</span><span class="special">,</span> <span class="identifier">ne</span><span class="special">,</span>
<span class="identifier">gt</span><span class="special">,</span> <span class="identifier">lt</span><span class="special">,</span> <span class="identifier">le</span><span class="special">,</span> <span class="identifier">ge</span><span class="special">,</span>
<span class="identifier">io</span></code> approach</strong></span>
</p>
<p>
This method is good if you're writing generic algorithms and need to use
operators from Boost.PFR only if there are no operators defined for the type:
</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">pfr</span><span class="special">/</span><span class="identifier">ops</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">uniform_comparator_less</span> <span class="special">{</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">lhs</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">rhs</span><span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span> <span class="special">{</span>
<span class="comment">// If T has operator&lt; or conversion operator then it is used.</span>
<span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">lt</span><span class="special">(</span><span class="identifier">lhs</span><span class="special">,</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
This methods effects are local to the function. It works even for local types,
like structures defined in functions.
</p>
<p>
<span class="bold"><strong>2. BOOST_PFR_FUNCTIONS_FOR(T) approach</strong></span>
</p>
<p>
This method is good if you're writing a structure and wish to define operators
for that structure.
</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">pfr</span><span class="special">/</span><span class="identifier">functions_for</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">pair_like</span> <span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">first</span><span class="special">;</span>
<span class="keyword">short</span> <span class="identifier">second</span><span class="special">;</span>
<span class="special">};</span>
<span class="identifier">BOOST_PFR_FUNCTIONS_FOR</span><span class="special">(</span><span class="identifier">pair_like</span><span class="special">)</span> <span class="comment">// Defines operators</span>
<span class="comment">// ...</span>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">pair_like</span><span class="special">{</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">}</span> <span class="special">&lt;</span> <span class="identifier">pair_like</span><span class="special">{</span><span class="number">1</span><span class="special">,</span> <span class="number">3</span><span class="special">});</span>
</pre>
<p>
Argument Dependant Lookup works well. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">less</span></code>
will find the operators for <code class="computeroutput"><span class="keyword">struct</span>
<span class="identifier">pair_like</span></code>. <code class="computeroutput"><a class="link" href="../BOOST_PFR_FUNCTIONS_FOR.html" title="Macro BOOST_PFR_FUNCTIONS_FOR">BOOST_PFR_FUNCTIONS_FOR(T)</a></code>
can not be used for local types. It does not respect conversion operators
of <code class="computeroutput"><span class="identifier">T</span></code>, so for example the
following code will output different values:
</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">pfr</span><span class="special">/</span><span class="identifier">functions_for</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">empty</span> <span class="special">{</span>
<span class="keyword">operator</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="string">"empty{}"</span><span class="special">;</span> <span class="special">}</span>
<span class="special">};</span>
<span class="comment">// Uncomment to get different output:</span>
<span class="comment">// BOOST_PFR_FUNCTIONS_FOR(empty)</span>
<span class="comment">// ...</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">empty</span><span class="special">{};</span> <span class="comment">// Outputs `empty{}` if BOOST_PFR_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.</span>
</pre>
<p>
<span class="bold"><strong>3. <code class="computeroutput"><span class="identifier">eq_fields</span><span class="special">,</span> <span class="identifier">ne_fields</span><span class="special">,</span> <span class="identifier">gt_fields</span><span class="special">,</span> <span class="identifier">lt_fields</span><span class="special">,</span> <span class="identifier">le_fields</span><span class="special">,</span> <span class="identifier">ge_fields</span><span class="special">,</span> <span class="identifier">io_fields</span></code>
approach</strong></span>
</p>
<p>
This method is good if you're willing to provide only some operators for
your type:
</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">pfr</span><span class="special">/</span><span class="identifier">io_fields</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">pair_like</span> <span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">first</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">second</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">inline</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">&lt;&lt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">os</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">pair_like</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">os</span> <span class="special">&lt;&lt;</span> <span class="identifier">bost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">io_fields</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
All the <code class="computeroutput"><span class="special">*</span><span class="identifier">_fields</span></code>
functions do ignore user defined operators and work only with fields of a
type. This makes them perfect for defining you own operators.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_pfr.tutorial.reflection_of_unions"></a><a class="link" href="tutorial.html#boost_pfr.tutorial.reflection_of_unions" title="Reflection of unions">Reflection of
unions </a>
</h3></div></div></div>
<p>
You could use tuple-like representation if a type contains union. But be
sure that operations for union are manually defined:
</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">pfr</span><span class="special">/</span><span class="identifier">ops</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">union</span> <span class="identifier">test_union</span> <span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">i</span><span class="special">;</span>
<span class="keyword">float</span> <span class="identifier">f</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">inline</span> <span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">==(</span><span class="identifier">test_union</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">test_union</span> <span class="identifier">r</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span> <span class="comment">// Compile time error without this operator</span>
<span class="keyword">bool</span> <span class="identifier">some_function</span><span class="special">(</span><span class="identifier">test_union</span> <span class="identifier">f1</span><span class="special">,</span> <span class="identifier">test_union</span> <span class="identifier">f2</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">pfr</span><span class="special">::</span><span class="identifier">eq</span><span class="special">(</span><span class="identifier">f1</span><span class="special">,</span> <span class="identifier">f2</span><span class="special">);</span> <span class="comment">// OK</span>
<span class="special">}</span>
</pre>
<p>
Reflection of unions is disabled in the Boost.PFR library for safety reasons.
Alas, there's no way to find out <span class="bold"><strong>active</strong></span>
member of a union and accessing an inactive member is an Undefined Behavior.
For example, library could always return the first member, but ostreaming
<code class="computeroutput"><span class="identifier">u</span></code> in <code class="computeroutput"><span class="keyword">union</span>
<span class="special">{</span><span class="keyword">char</span><span class="special">*</span> <span class="identifier">c</span><span class="special">;</span>
<span class="keyword">long</span> <span class="keyword">long</span>
<span class="identifier">ll</span><span class="special">;</span> <span class="special">}</span> <span class="identifier">u</span><span class="special">;</span>
<span class="identifier">u</span><span class="special">.</span><span class="identifier">ll</span><span class="special">=</span> <span class="number">1</span><span class="special">;</span></code> will crash your program with an invalid
pointer dereference.
</p>
<p>
Any attempt to reflect unions leads to a compile time error. In many cases
a static assert is triggered that outputs the following message:
</p>
<pre class="programlisting"><span class="identifier">error</span><span class="special">:</span> <span class="keyword">static_assert</span> <span class="identifier">failed</span> <span class="string">"====================&gt; Boost.PFR: For safety reasons it is forbidden
to reflect unions. See `Reflection of unions` section in the docs for more info."</span>
</pre>
</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 © 2016-2021 Antony Polukhin<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="short_examples_for_the_impatient.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../boost_pfr.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="limitations_and_configuration.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>