mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-09 23:14:04 +00:00
1322 lines
84 KiB
HTML
1322 lines
84 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
|
|
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>Boost.MultiIndex Documentation - Advanced topics</title>
|
|
<link rel="stylesheet" href="style.css" type="text/css">
|
|
</head>
|
|
|
|
<body>
|
|
<h1><img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
|
|
"middle" width="277" height="86">Boost.MultiIndex Advanced topics</h1>
|
|
|
|
<div class="prev_link"><a href="tutorial.html"><img src="prev.gif" alt="tutorial" border="0"><br>
|
|
Tutorial
|
|
</a></div>
|
|
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
|
|
Index
|
|
</a></div>
|
|
<div class="next_link"><a href="reference/index.html"><img src="next.gif" alt="reference" border="0"><br>
|
|
Reference
|
|
</a></div><br clear="all" style="clear: all;">
|
|
|
|
<hr>
|
|
|
|
<h2>Contents</h2>
|
|
|
|
<ul>
|
|
<li><a href="#composite_keys">Composite keys</a></li>
|
|
<li><a href="#advanced_key_extractors">Advanced features of Boost.MultiIndex key
|
|
extractors</a>
|
|
<ul>
|
|
<li><a href="#member_offset">Use of <code>member_offset</code></a></li>
|
|
<li><a href="#mem_fun_explicit">Use of <code>const_mem_fun_explicit</code> and
|
|
<code>mem_fun_explicit</code></a></li>
|
|
<li><a href="#composite_key_no_pts"><code>composite_key</code> in compilers
|
|
without partial template specialization</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#ctor_args_list">Use of <code>ctor_args_list</code></a></li>
|
|
<li><a href="#debugging_support">Debugging support</a>
|
|
<ul>
|
|
<li><a href="#safe_mode">Safe mode</a></li>
|
|
<li><a href="#invariant_check">Invariant-checking mode</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#simulate_std_containers">Simulating standard containers with
|
|
<code>multi_index_container</code></a>
|
|
<ul>
|
|
<li><a href="#simulate_assoc_containers">Simulation of associative
|
|
containers</a></li>
|
|
<li><a href="#simulate_std_list">Simulation of <code>std::list</code></a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#metaprogrammming">Metaprogramming and <code>multi_index_container</code></a>
|
|
<ul>
|
|
<li><a href="#mpl_analysis">MPL analysis</a></li>
|
|
<li><a href="#mpl_synthesis">MPL synthesis</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h2><a name="composite_keys">Composite keys</a></h2>
|
|
|
|
<p>
|
|
In relational databases, composite keys depend on two or more fields of a given table.
|
|
The analogous concept in Boost.MultiIndex is modeled by means of
|
|
<a href="reference/key_extraction.html#composite_key">
|
|
<code>composite_key</code></a>, as shown in the example:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>phonebook_entry</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>;</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>;</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>;</span>
|
|
|
|
<span class=identifier>phonebook_entry</span><span class=special>(</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>,</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>,</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>):</span>
|
|
<span class=identifier>family_name</span><span class=special>(</span><span class=identifier>family_name</span><span class=special>),</span><span class=identifier>given_name</span><span class=special>(</span><span class=identifier>given_name</span><span class=special>),</span><span class=identifier>phone_number</span><span class=special>(</span><span class=identifier>phone_number</span><span class=special>)</span>
|
|
<span class=special>{}</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=comment>// define a multi_index_container with a composite key on
|
|
// (family_name,given_name)</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=comment>//non-unique as some subscribers might have more than one number</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span>
|
|
<span class=identifier>composite_key</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span> <span class=comment>// unique as numbers belong to only one subscriber</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>phonebook</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
<code>composite_key</code> accepts two or more key extractors on the same
|
|
value (here, <code>phonebook_entry</code>). Lookup operations on a composite
|
|
key are accomplished by passing tuples with the values searched:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
|
|
<span class=special>...</span>
|
|
<span class=comment>// search for Dorothea White's number</span>
|
|
<span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>=</span><span class=identifier>pb</span><span class=special>.</span><span class=identifier>find</span><span class=special>(</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>(</span><span class=string>"White"</span><span class=special>),</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>(</span><span class=string>"Dorothea"</span><span class=special>)));</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>number</span><span class=special>=</span><span class=identifier>it</span><span class=special>-></span><span class=identifier>phone_number</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Composite keys are sorted by lexicographical order, i.e. sorting is performed
|
|
by the first key, then the second key if the first one is equal, etc. This
|
|
order allows for partial searches where only the first keys are specified:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
|
|
<span class=special>...</span>
|
|
<span class=comment>// look for all Whites</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>phonebook</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>></span> <span class=identifier>p</span><span class=special>=</span>
|
|
<span class=identifier>pb</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>(</span><span class=string>"White"</span><span class=special>)));</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
On the other hand, partial searches without specifying the first keys are not
|
|
allowed.
|
|
</p>
|
|
|
|
<p>
|
|
By default, the corresponding <code>std::less</code> predicate is used
|
|
for each subkey of a composite key. Alternate comparison predicates can
|
|
be specified with <a href="reference/key_extraction.html#composite_key_compare">
|
|
<code>composite_key_compare</code></a>:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// phonebook with given names in reverse order</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span>
|
|
<span class=identifier>composite_key</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>composite_key_compare</span><span class=special><</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>>,</span> <span class=comment>// family names sorted as by default</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>></span> <span class=comment>// given names reversed</span>
|
|
<span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>phonebook</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
See <a href="examples.html#example7">Example 7</a> in the examples section
|
|
for an application of <code>composite_key</code>.
|
|
</p>
|
|
|
|
<h2><a name="advanced_key_extractors">Advanced features of Boost.MultiIndex key
|
|
extractors</a></h2>
|
|
|
|
<p>
|
|
The <a href="reference/key_extraction.html#key_extractors"><code>Key Extractor</code></a>
|
|
concept allows the same object to extract keys from several different types,
|
|
possibly through suitably defined overloads of <code>operator()</code>:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// example of a name extractor from employee and employee *</span>
|
|
<span class=keyword>struct</span> <span class=identifier>name_extractor</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>e</span><span class=special>.</span><span class=identifier>name</span><span class=special>;}</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>employee</span><span class=special>&</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>e</span><span class=special>.</span><span class=identifier>name</span><span class=special>;}</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>employee</span><span class=special>*</span> <span class=identifier>e</span><span class=special>)</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>e</span><span class=special>-></span><span class=identifier>name</span><span class=special>;}</span>
|
|
<span class=special>};</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
This possibility is fully exploited by predefined key extractors provided
|
|
by Boost.MultiIndex, making it simpler to define <code>multi_index_container</code>s
|
|
where elements are pointers or references to the actual objects. The following
|
|
specifies a <code>multi_index_container</code> of pointers to employees sorted by their
|
|
names.
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>employee</span> <span class=special>*,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>></span> <span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>employee_set</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Note that this is specified in exactly the same manner as a <code>multi_index_container</code>
|
|
of actual <code>employee</code> objects: <code>member</code> takes care of the
|
|
extra dereferencing needed to gain access to <code>employee::name</code>. A similar
|
|
functionality is provided for interoperability with reference wrappers from
|
|
<a href="../../../doc/html/ref.html">Boost.Ref</a>:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>reference_wrapper</span><span class=special><</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>></span> <span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>employee_set</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
In fact, support for pointers is further extended to accept what we call
|
|
<i>chained pointers</i>. Such a chained pointer is defined by induction as a raw or
|
|
smart pointer or iterator to the actual element, to a reference wrapper of the
|
|
element or <i>to another chained pointer</i>; that is, chained pointers are arbitrary
|
|
compositions of pointer-like types ultimately dereferencing
|
|
to the element from where the key is to be extracted. Examples of chained
|
|
pointers to <code>employee</code> are:
|
|
<ul>
|
|
<li><code>employee *</code>,</li>
|
|
<li><code>const employee *</code>,</li>
|
|
<li><code>std::auto_ptr<employee></code>,</li>
|
|
<li><code>std::list<boost::reference_wrapper<employee> >::iterator</code>,</li>
|
|
<li><code>employee **</code>,</li>
|
|
<li><code>boost::shared_ptr<const employee *></code>.</li>
|
|
</ul>
|
|
In general, chained pointers with dereferencing distance greater than 1 are not
|
|
likely to be used in a normal program, but they can arise in frameworks
|
|
which construct "views" as <code>multi_index_container</code>s from preexisting
|
|
<code>multi_index_container</code>s.
|
|
</p>
|
|
|
|
<p>
|
|
In order to present a short summary of the different usages of Boost.MultiIndex
|
|
key extractors in the presence of reference wrappers and pointers, consider the
|
|
following final type:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>T</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>int</span> <span class=identifier>i</span><span class=special>;</span>
|
|
<span class=keyword>const</span> <span class=keyword>int</span> <span class=identifier>j</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>f</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>g</span><span class=special>();</span>
|
|
<span class=special>};</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The table below lists the appropriate key extractors to be used for
|
|
different pointer and reference wrapper types based on <code>T</code>, for
|
|
each of its members.
|
|
</p>
|
|
|
|
<p align="center">
|
|
<table cellspacing="0">
|
|
<caption><b>Use cases for Boost.MultiIndex key extractors.</b></caption>
|
|
<tr>
|
|
<th>element type</th>
|
|
<th>sorted by</th>
|
|
<th>key extractor</th>
|
|
<th>applicable to<br><code>const</code> elements?</th>
|
|
<th>read/write?</th>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" rowspan="4"><code>T</code></td>
|
|
<td><code>i</code></td>
|
|
<td><code>member<T,int,&T::i></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">yes</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>j</code></td>
|
|
<td><code>member<T,const int,&T::j></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>f()</code></td>
|
|
<td><code>const_mem_fun<T,int,&T::f></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>g()</code></td>
|
|
<td><code>mem_fun<T,int,&T::g></code></td>
|
|
<td align="center">no</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
|
|
<tr class="odd_tr">
|
|
<td align="center" rowspan="4"><code>reference_wrapper<T></code></td>
|
|
<td><code>i</code></td>
|
|
<td><code>member<T,int,&T::i></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">yes</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>j</code></td>
|
|
<td><code>member<T,const int,&T::j></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>f()</code></td>
|
|
<td><code>const_mem_fun<T,int,&T::f></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>g()</code></td>
|
|
<td><code>mem_fun<T,int,&T::g></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="center" rowspan="4"><code>reference_wrapper<const T></code></td>
|
|
<td><code>i</code></td>
|
|
<td><code>member<T,const int,&T::i></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>j</code></td>
|
|
<td><code>member<T,const int,&T::j></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>f()</code></td>
|
|
<td><code>const_mem_fun<T,int,&T::f></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>g()</code></td>
|
|
<td colspan="3"> </td>
|
|
</tr>
|
|
|
|
<tr class="odd_tr">
|
|
<td align="center" rowspan="4">chained pointer to <code>T</code><br>
|
|
or to <code>reference_wrapper<T></code></td>
|
|
<td><code>i</code></td>
|
|
<td><code>member<T,int,&T::i></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">yes</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>j</code></td>
|
|
<td><code>member<T,const int,&T::j></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>f()</code></td>
|
|
<td><code>const_mem_fun<T,int,&T::f></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr class="odd_tr">
|
|
<td><code>g()</code></td>
|
|
<td><code>mem_fun<T,int,&T::g></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="center" rowspan="4">chained pointer to <code>const T</code><br>
|
|
or to <code>reference_wrapper<const T></code></td>
|
|
<td><code>i</code></td>
|
|
<td><code>member<T,const int,&T::i></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>j</code></td>
|
|
<td><code>member<T,const int,&T::j></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>f()</code></td>
|
|
<td><code>const_mem_fun<T,int,&T::f></code></td>
|
|
<td align="center">yes</td>
|
|
<td align="center">no</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>g()</code></td>
|
|
<td colspan="3"> </td>
|
|
</tr>
|
|
|
|
</table>
|
|
</p>
|
|
|
|
<p>
|
|
The column "applicable to <code>const</code> elements?" states whether the
|
|
corresponding key extractor can be used when passed constant elements (this
|
|
relates to the elements specified in the first column, not the referenced
|
|
<code>T</code> objects). The only negative case is for <code>T::g</code> when
|
|
the elements are raw <code>T</code> objects, which make sense as we are dealing
|
|
with a non-constant member function: this also implies that <code>multi_index_container</code>s
|
|
of elements of <code>T</code> cannot be sorted by <code>T::g</code>, because
|
|
elements contained within a <code>multi_index_container</code> are treated as constant.
|
|
</p>
|
|
|
|
<p>
|
|
A key extractor is called <i>read/write</i> if it returns a non-constant reference
|
|
to the key when passed a non-constant element, and it is called <i>read-only</i>
|
|
otherwise. In order to use <code>multi_index_container::modify_key</code>, the associated
|
|
key extractor must be read/write. The column "read/write?" shows that most
|
|
combinations yield read-only extractors.
|
|
</p>
|
|
|
|
<p>
|
|
Some care has to be taken to preserve <code>const</code>-correctness in the
|
|
specification of the key extractors: in some sense, the <code>const</code>
|
|
qualifier is carried along to the member part, even if that particular
|
|
member is not defined as <code>const</code>. For instance, if the elements
|
|
are of type <code>const T *</code>, sorting by <code>T::i</code> is <i>not</i>
|
|
specified as <code>member<const T,int,&T::i></code>, but rather as
|
|
<code>member<T,const int,&T::i></code>.
|
|
</p>
|
|
|
|
<p>
|
|
For practical demonstrations of use of these key extractors, refer to
|
|
<a href="examples.html#example2">example 2</a> and
|
|
<a href="examples.html#example6">example 6</a> in the examples section.
|
|
</p>
|
|
|
|
<h3><a name="member_offset">Use of <code>member_offset</code></a></h3>
|
|
|
|
<p>
|
|
The <code>member</code> key extractor poses some problems in compilers
|
|
that do not properly support pointers to members as non-type
|
|
template arguments. The following compilers have been confirmed not
|
|
to work correctly with <code>member</code>:
|
|
<ul>
|
|
<li>MSVC++ 6.0,
|
|
<li>Intel C++ 7.0/7.1 for Windows.
|
|
</ul>
|
|
In these cases, a replacement utility
|
|
<a href="reference/key_extraction.html#member_offset"><code>member_offset</code></a>
|
|
has been provided that does the work of <code>member</code> at the
|
|
expense of less convenient notation and the possibility of
|
|
non-conformance with the standard. Please consult
|
|
the reference for further information on <code>member_offset</code>.
|
|
<p>
|
|
|
|
<p>
|
|
The following test program can help determine if your compiler
|
|
properly supports pointers to members as non-type template parameters:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span>
|
|
<span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>utility</span><span class=special>></span>
|
|
<span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>iostream</span><span class=special>></span>
|
|
|
|
<span class=keyword>using</span> <span class=keyword>namespace</span> <span class=identifier>std</span><span class=special>;</span>
|
|
<span class=keyword>using</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>member</span><span class=special>;</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=keyword>int</span><span class=special>,</span><span class=keyword>int</span><span class=special>></span> <span class=identifier>pair_of_ints</span><span class=special>;</span>
|
|
|
|
<span class=keyword>int</span> <span class=identifier>main</span><span class=special>()</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>pair_of_ints</span> <span class=identifier>p</span><span class=special>(</span><span class=number>0</span><span class=special>,</span><span class=number>1</span><span class=special>);</span>
|
|
<span class=keyword>int</span> <span class=identifier>i</span><span class=special>=</span><span class=identifier>member</span><span class=special><</span><span class=identifier>pair_of_ints</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>pair_of_ints</span><span class=special>::</span><span class=identifier>first</span><span class=special>>()(</span><span class=identifier>p</span><span class=special>);</span>
|
|
<span class=keyword>int</span> <span class=identifier>j</span><span class=special>=</span><span class=identifier>member</span><span class=special><</span><span class=identifier>pair_of_ints</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>pair_of_ints</span><span class=special>::</span><span class=identifier>second</span><span class=special>>()(</span><span class=identifier>p</span><span class=special>);</span>
|
|
<span class=keyword>if</span><span class=special>(</span><span class=identifier>i</span><span class=special>!=</span><span class=number>0</span><span class=special>||</span><span class=identifier>j</span><span class=special>!=</span><span class=number>1</span><span class=special>){</span>
|
|
<span class=identifier>cout</span><span class=special><<</span><span class=string>"WARNING: compiler does not properly support\n"</span>
|
|
<span class=string>"pointers as non-type template parameters"</span><span class=special><<</span><span class=identifier>endl</span><span class=special>;</span>
|
|
<span class=keyword>return</span> <span class=number>1</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=identifier>cout</span><span class=special><<</span><span class=string>"test succesful"</span><span class=special><<</span><span class=identifier>endl</span><span class=special>;</span>
|
|
<span class=keyword>return</span> <span class=number>0</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
If you find a compiler not listed here that does not pass the test,
|
|
please report to the maintainer of the library. As an example of use,
|
|
given the class</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>class</span> <span class=identifier>A</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>int</span> <span class=identifier>x</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
the instantiation <code>member<A,int,&A::x></code> can be simulated then
|
|
as <code>member_offset<A,int,offsetof(A,x)></code>.
|
|
</p>
|
|
|
|
<p>
|
|
For those writing portable code, Boost.MultiIndex provides the ternary macro
|
|
<code>BOOST_MULTI_INDEX_MEMBER</code>. Continuing with the example above, the
|
|
expression
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>BOOST_MULTI_INDEX_MEMBER</span><span class=special>(</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,</span><span class=identifier>x</span><span class=special>)</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
expands to either
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>A</span><span class=special>::</span><span class=identifier>x</span><span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
or alternatively to
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>member_offset</span><span class=special><</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,</span><span class=identifier>offsetof</span><span class=special>(</span><span class=identifier>A</span><span class=special>,</span><span class=identifier>x</span><span class=special>)></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
depending on whether the current compiler supports pointer to members as
|
|
non-type template arguments or not. The alternative expansion is driven by
|
|
the defect macro <code>BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS</code>,
|
|
which has been proposed for inclusion in the
|
|
<a href="../../../libs/config/config.htm">Boost Configuration Library</a>.
|
|
Until the defect macro is accepted, Boost.MultiIndex treats it as if defined for
|
|
<ul>
|
|
<li>MSVC++ 6.0 or lower,
|
|
<li>Intel C++ 7.1 or lower for Windows.
|
|
</ul>
|
|
If you detect this defect in a compiler other than these, you can take
|
|
advantage of <code>BOOST_MULTI_INDEX_MEMBER</code> by manually defining
|
|
<code>BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS</code> prior to the
|
|
inclusion of Boost.MultiIndex headers.
|
|
</p>
|
|
|
|
<h3><a name="mem_fun_explicit">Use of <code>const_mem_fun_explicit</code> and
|
|
<code>mem_fun_explicit</code></a></h3>
|
|
|
|
<p>
|
|
MSVC++ 6.0 has problems with <code>const</code> member functions as non-type
|
|
template parameters, and thus does not accept the <code>const_mem_fun</code>
|
|
key extractor. A simple workaround, fortunately, has been found, consisting
|
|
in specifying the <i>type</i> of these pointers as an additional template
|
|
parameter. The alternative <code>const_mem_fun_explicit</code> extractor
|
|
adopts this solution; for instance, given the type
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>A</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>int</span> <span class=identifier>f</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
the extractor <code>const_mem_fun<A,int,&A::f></code> can be replaced by
|
|
<code>const_mem_fun_explicit<A,int,int (A::*)()const,&A::f></code>. A similar
|
|
<code>mem_fun_explicit</code> class template is provided for non-constant
|
|
member functions.
|
|
</p>
|
|
|
|
<p>
|
|
If you are writing cross-platform code, the selection of either key extractor
|
|
is transparently handled by the macro <code>BOOST_MULTI_INDEX_CONST_MEM_FUN</code>,
|
|
so that
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>BOOST_MULTI_INDEX_CONST_MEM_FUN</span><span class=special>(</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,</span><span class=identifier>f</span><span class=special>)</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
expands by default to
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>const_mem_fun</span><span class=special><</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>A</span><span class=special>::</span><span class=identifier>f</span><span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
but resolves to
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>const_mem_fun_explicit</span><span class=special><</span><span class=identifier>A</span><span class=special>,</span><span class=keyword>int</span><span class=special>,</span><span class=keyword>int</span> <span class=special>(</span><span class=identifier>A</span><span class=special>::*)()</span><span class=keyword>const</span><span class=special>,&</span><span class=identifier>A</span><span class=special>::</span><span class=identifier>f</span><span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
in MSVC++ 6.0. An analogous macro <code>BOOST_MULTI_INDEX_MEM_FUN</code> is
|
|
provided as well.
|
|
</p>
|
|
|
|
<h3><a name="composite_key_no_pts"><code>composite_key</code> in compilers
|
|
without partial template specialization</a></h3>
|
|
|
|
<p>
|
|
Much of the power of <code>composite_key</code> derives from the ability
|
|
to perform searches when only the first elements of the compound key are
|
|
given. In order to enable this functionality, <code>std::less</code> and
|
|
<code>std::greater</code> are specialized for
|
|
<a href="reference/key_extraction.html#composite_key_result">
|
|
<code>composite_key_result</code></a> instantiations to provide
|
|
overloads accepting tuples of values.
|
|
</p>
|
|
|
|
<p>
|
|
In those compilers that do not support partial template specialization,
|
|
tuple-based comparisons are not available by default. In this case,
|
|
<code>multi_index_container</code> instantiations using composite keys
|
|
will work as expected (elements are sorted lexicographically on the
|
|
results of the combined keys), except that lookup operations will not
|
|
accept tuples as an argument. The most obvious workaround
|
|
to this deficiency involves explicitly specifying the comparison
|
|
predicate with <code>composite_key_compare</code>: this is tedious as
|
|
the comparison predicates for all the element key extractors must be
|
|
explicitly typed. For this reason, Boost.MultiIndex provides the replacement
|
|
class template
|
|
<a href="reference/key_extraction.html#composite_key_result_less">
|
|
<code>composite_key_result_less</code></a>, that
|
|
acts as the missing specialization of <code>std::less</code> for
|
|
<code>composite_key_result</code>s:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>composite_key</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>ckey_t</span><span class=special>;</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>phonebook_entry</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span>
|
|
<span class=identifier>ckey_t</span><span class=special>,</span>
|
|
<span class=comment>// composite_key_result_less plays the role of
|
|
// std::less<ckey_t::result_type></span>
|
|
<span class=identifier>composite_key_result_less</span><span class=special><</span><span class=identifier>ckey_t</span><span class=special>::</span><span class=identifier>result_type</span><span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>phonebook_entry</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,&</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>phonebook</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
There is also an analogous
|
|
<a href="reference/key_extraction.html#composite_key_result_greater">
|
|
<code>composite_key_result_greater</code></a> class to substitute for
|
|
specializations of <code>std::greater</code>.
|
|
</p>
|
|
|
|
<h2><a name="ctor_args_list">Use of <code>ctor_args_list</code></a></h2>
|
|
|
|
<p>
|
|
Although in most cases <code>multi_index_container</code>s will be default constructed
|
|
(or copied from a preexisting <code>multi_index_container</code>), sometimes it is
|
|
necessary to specify particular values for the internal objects used (key extractors,
|
|
comparison predicates, allocator), for instance if some of these objects do not have
|
|
a default constructor. The same situation can arise with standard STL containers,
|
|
which allow for the optional specification of such objects:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// example of non-default constructed std::set</span>
|
|
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>IntegralType</span><span class=special>></span>
|
|
<span class=keyword>struct</span> <span class=identifier>modulo_less</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>modulo_less</span><span class=special>(</span><span class=identifier>IntegralType</span> <span class=identifier>m</span><span class=special>):</span><span class=identifier>modulo</span><span class=special>(</span><span class=identifier>m</span><span class=special>){}</span>
|
|
|
|
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=identifier>IntegralType</span> <span class=identifier>x</span><span class=special>,</span><span class=identifier>IntegralType</span> <span class=identifier>y</span><span class=special>)</span><span class=keyword>const</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>return</span> <span class=special>(</span><span class=identifier>x</span><span class=special>%</span><span class=identifier>modulo</span><span class=special>)<(</span><span class=identifier>y</span><span class=special>%</span><span class=identifier>modulo</span><span class=special>);</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=keyword>private</span><span class=special>:</span>
|
|
<span class=identifier>IntegralType</span> <span class=identifier>modulo</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>,</span><span class=identifier>modulo_less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>></span> <span class=special>></span> <span class=identifier>modulo_set</span><span class=special>;</span>
|
|
|
|
<span class=identifier>modulo_set</span> <span class=identifier>m</span><span class=special>(</span><span class=identifier>modulo_less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>(</span><span class=number>10</span><span class=special>));</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
<code>multi_index_container</code> does also provide this functionality, though in a
|
|
considerably more complex fashion, due to the fact that the constructor
|
|
of a <code>multi_index_container</code> has to accept values for all the internal
|
|
objects of its indices. The full form of <code>multi_index_container</code> constructor
|
|
is
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>explicit</span> <span class=identifier>multi_index_container</span><span class=special>(</span>
|
|
<span class=keyword>const</span> <span class=identifier>ctor_args_list</span><span class=special>&</span> <span class=identifier>args_list</span><span class=special>=</span><span class=identifier>ctor_args_list</span><span class=special>(),</span>
|
|
<span class=keyword>const</span> <span class=identifier>allocator_type</span><span class=special>&</span> <span class=identifier>al</span><span class=special>=</span><span class=identifier>allocator_type</span><span class=special>());</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The specification of the allocator object poses no particular problems;
|
|
as for the <code>ctor_args_list</code>, this object is designed so as to hold
|
|
the necessary construction values for every index in the <code>multi_index_container</code>.
|
|
From the point of view of the user, <code>ctor_args_list</code> is equivalent
|
|
to the type
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special><</span><span class=identifier>C<sub>0</sub></span><span class=special>,...,</span><span class=identifier>C<sub>I-1</sub></span><span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
where <code>I</code> is the number of indices, and <code>C<sub>i</sub></code> is
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>nth_index</span><span class=special><</span><span class=identifier>i</span><span class=special>>::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
that is, the nested type <code>ctor_args</code> of the <code>i</code>-th index. Each
|
|
<code>ctor_args</code> type is in turn a tuple holding values for constructor
|
|
arguments of the associated index: so, ordered indices demand a key extractor object
|
|
and a comparison predicate, while sequenced indices do not need any construction
|
|
argument. For instance, given the definition
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>></span> <span class=special>>,</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>,</span> <span class=identifier>modulo_less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>></span> <span class=special>>,</span>
|
|
<span class=identifier>sequenced</span><span class=special><></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>modulo_indexed_set</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
the corresponding <code>ctor_args_list</code> type is equivalent to
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special><</span>
|
|
<span class=comment>// ctr_args of index #0</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>></span> <span class=special>>,</span>
|
|
|
|
<span class=comment>// ctr_args of index #1</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>,</span><span class=identifier>modulo_less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>></span> <span class=special>>,</span>
|
|
|
|
<span class=comment>// sequenced indices do not have any construction argument</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>tuple</span><span class=special><></span>
|
|
<span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Such a <code>modulo_indexed_set</code> cannot be default constructed, because
|
|
<code>modulo_less</code> does not provide a default constructor. The following shows
|
|
how the construction can be done:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>ctor_args_list</span> <span class=identifier>args_list</span><span class=special>=</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span>
|
|
<span class=comment>// ctor_args for index #0 is default constructible</span>
|
|
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special><</span><span class=number>0</span><span class=special>>::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span><span class=special>(),</span>
|
|
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>(),</span><span class=identifier>modulo_less</span><span class=special><</span><span class=keyword>unsigned</span> <span class=keyword>int</span><span class=special>>(</span><span class=number>10</span><span class=special>)),</span>
|
|
|
|
<span class=comment>// this is also default constructible (actually, an empty tuple)</span>
|
|
<span class=identifier>modulo_indexed_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special><</span><span class=number>2</span><span class=special>>::</span><span class=identifier>type</span><span class=special>::</span><span class=identifier>ctor_args</span><span class=special>(),</span>
|
|
<span class=special>);</span>
|
|
|
|
<span class=identifier>modulo_indexed_set</span> <span class=identifier>m</span><span class=special>(</span><span class=identifier>args_list</span><span class=special>);</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
A program is provided in the <a href="examples.html#example3">examples section</a> that
|
|
puts in practise these concepts.
|
|
</p>
|
|
|
|
<h2><a name="debugging_support">Debugging support</a></h2>
|
|
|
|
<p>
|
|
The concept of <i>Design by Contract</i>, originally developed as part
|
|
of Bertrand Meyer's <a href="http://www.eiffel.com">Eiffel</a> language,
|
|
revolves around the formulation of a <i>contract</i> between the user
|
|
of a library and the implementor, by which the first is required to
|
|
respect some <i>preconditions</i> on the values passed when invoking
|
|
methods of the library, and the implementor guarantees in return
|
|
that certain constraints on the results are met (<i>postconditions</i>),
|
|
as well as the honoring of specified internal consistency rules, called
|
|
<i>invariants</i>. Eiffel natively supports the three parts of the
|
|
contract just described by means of constructs <code>require</code>,
|
|
<code>ensure</code> and <code>invariant</code>, respectively.
|
|
</p>
|
|
|
|
<p>
|
|
C++ does not enjoy direct support for Design by Contract techniques: these
|
|
are customarily implemented as assertion code, often turned off in
|
|
release mode for performance reasons. Following this approach,
|
|
Boost.MultiIndex provides two distinct debugging modes:
|
|
<ul>
|
|
<li><i>Safe mode</i> checks preconditions on the invocations to the
|
|
facilities of the library,</li>
|
|
<li><i>invariant-checking mode</i> performs post-execution checks aimed
|
|
at ensuring that the internal consistency of the library is preserved.
|
|
</ul>
|
|
These two modes are independent of each other and can be set on or off
|
|
individually. It is important to note that errors detected by safe mode are
|
|
due in principle to faulty code in the user's program, while
|
|
invariant-checking mode detects potential <i>internal</i> bugs in the
|
|
implementation of Boost.MultiIndex.
|
|
</p>
|
|
|
|
<h3><a name="safe_mode">Safe mode</a></h3>
|
|
|
|
<p>
|
|
The idea of adding precondition checking facilities to STL as a debugging aid
|
|
was first introduced by Cay S. Horstmann in his
|
|
<a href="http://www.horstmann.com/safestl.html">Safe STL</a> library and later
|
|
adopted by <a href="http://www.stlport.org/doc/debug_mode.html">STLport Debug
|
|
Mode</a>. Similarly, Boost.MultiIndex features the so-called <i>safe mode</i>
|
|
in which all sorts of preconditions are checked when dealing with iterators
|
|
and functions of the library.
|
|
</p>
|
|
|
|
<p>
|
|
Boost.MultiIndex safe mode is set by globally defining the macro
|
|
<code>BOOST_MULTI_INDEX_ENABLE_SAFE_MODE</code>. Error conditions
|
|
are checked via the macro <code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code>, which
|
|
by default resolves to a call to <a href="../../../libs/utility/assert.html">
|
|
<code>BOOST_ASSERT</code></a>.
|
|
</p>
|
|
|
|
<p>
|
|
If the user decides to define her own version of
|
|
<code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code>, it has to take the form
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</span><span class=special>(</span><span class=identifier>expr</span><span class=special>,</span><span class=identifier>error_code</span><span class=special>)</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
where <code>expr</code> is the condition checked and <code>error_code</code>
|
|
is one value of the <code>safe_mode::error_code</code> enumeration:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
|
|
|
|
<span class=keyword>namespace</span> <span class=identifier>multi_index</span><span class=special>{</span>
|
|
|
|
<span class=keyword>namespace</span> <span class=identifier>safe_mode</span><span class=special>{</span>
|
|
|
|
<span class=keyword>enum</span> <span class=identifier>error_code</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>invalid_iterator</span><span class=special>,</span> <span class=comment>// default initialized iterator</span>
|
|
<span class=identifier>not_dereferenceable_iterator</span><span class=special>,</span> <span class=comment>// iterator is not dereferenceable</span>
|
|
<span class=identifier>not_incrementable_iterator</span><span class=special>,</span> <span class=comment>// iterator points to end of sequence</span>
|
|
<span class=identifier>not_decrementable_iterator</span><span class=special>,</span> <span class=comment>// iterator points to beginning of sequence</span>
|
|
<span class=identifier>not_owner</span><span class=special>,</span> <span class=comment>// iterator does not belong to the container</span>
|
|
<span class=identifier>not_same_owner</span><span class=special>,</span> <span class=comment>// iterators belong to different containers</span>
|
|
<span class=identifier>invalid_range</span><span class=special>,</span> <span class=comment>// last not reachable from first</span>
|
|
<span class=identifier>inside_range</span><span class=special>,</span> <span class=comment>// iterator lies within a range (and it mustn't)</span>
|
|
<span class=identifier>same_container</span> <span class=comment>// containers ought to be different</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=special>}</span> <span class=comment>// namespace multi_index::safe_mode</span>
|
|
|
|
<span class=special>}</span> <span class=comment>// namespace multi_index</span>
|
|
|
|
<span class=special>}</span> <span class=comment>// namespace boost</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
For instance, the following replacement of
|
|
<code>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</code> throws an exception instead of
|
|
asserting:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>/</span><span class=identifier>safe_mode_errors</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span>
|
|
|
|
<span class=keyword>struct</span> <span class=identifier>safe_mode_exception</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>safe_mode_exception</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>safe_mode</span><span class=special>::</span><span class=identifier>error_code</span> <span class=identifier>error_code</span><span class=special>):</span>
|
|
<span class=identifier>error_code</span><span class=special>(</span><span class=identifier>error_code</span><span class=special>)</span>
|
|
<span class=special>{}</span>
|
|
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>multi_index</span><span class=special>::</span><span class=identifier>safe_mode</span><span class=special>::</span><span class=identifier>error_code</span> <span class=identifier>error_code</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=preprocessor>#define</span> <span class=identifier>BOOST_MULTI_INDEX_SAFE_MODE_ASSERT</span><span class=special>(</span><span class=identifier>expr</span><span class=special>,</span><span class=identifier>error_code</span><span class=special>)</span> <span class=special>\</span>
|
|
<span class=keyword>if</span><span class=special>(!(</span><span class=identifier>expr</span><span class=special>)){</span><span class=keyword>throw</span> <span class=identifier>safe_mode_exception</span><span class=special>(</span><span class=identifier>error_code</span><span class=special>);}</span>
|
|
|
|
<span class=comment>// This has to go before the inclusion of any header from Boost.MultiIndex,
|
|
// except possibly safe_error_codes.hpp.</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Other possibilites, like outputting to a log or firing some kind of alert, are
|
|
also implementable.
|
|
</p>
|
|
|
|
<p>
|
|
<b>Warning:</b> Safe mode adds a very important overhead to the program
|
|
both in terms of space and time used, so in general it should not be set for
|
|
<code>NDEBUG</code> builds. Also, this mode is intended solely as a debugging aid,
|
|
and programs must not rely on it as part of their normal execution flow: in
|
|
particular, no guarantee is made that all possible precondition errors are diagnosed,
|
|
or that the checks remain stable across different versions of the library.
|
|
</p>
|
|
|
|
<h3><a name="invariant_check">Invariant-checking mode</a></h3>
|
|
|
|
<p>
|
|
The so called <i>invariant-checking mode</i> of Boost.MultiIndex can be
|
|
set by globally defining the macro
|
|
<code>BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING</code>.
|
|
When this mode is in effect, all public functions of Boost.MultiIndex
|
|
will perform post-execution tests aimed at ensuring that the basic
|
|
internal invariants of the data structures managed are preserved.
|
|
</p>
|
|
|
|
<p>
|
|
If an invariant test fails, Boost.MultiIndex will indicate the failure
|
|
by means of the unary macro <code>BOOST_MULTI_INDEX_INVARIANT_ASSERT</code>.
|
|
Unless the user provides a definition for this macro, it defaults to
|
|
<a href="../../../libs/utility/assert.html">
|
|
<code>BOOST_ASSERT</code></a>. Any assertion of this kind should
|
|
be regarded in principle as a bug in the library. Please report such
|
|
problems, along with as much contextual information as possible, to the
|
|
maintainer of the library.
|
|
</p>
|
|
|
|
<p>
|
|
It is recommended that users of Boost.MultiIndex always set the
|
|
invariant-checking mode in debug builds.
|
|
</p>
|
|
|
|
<h2><a name="simulate_std_containers">Simulating standard containers with
|
|
<code>multi_index_container</code></a></h2>
|
|
|
|
<h3><a name="simulate_assoc_containers">Simulation of associative
|
|
containers</a></h3>
|
|
|
|
<p>
|
|
Academic movitations aside, there is a practical interest in simulating standard
|
|
associative containers by means of <code>multi_index_container</code>, namely to take
|
|
advantage of extended functionalities provided by <code>multi_index_container</code> for
|
|
lookup, range querying and updating.
|
|
</p>
|
|
|
|
<p>
|
|
In order to simulate a <code>std::set</code> one can follow the substitution
|
|
rule:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Key</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=identifier>Key</span><span class=special>>,</span><span class=identifier>Compare</span><span class=special>></span> <span class=special>>,</span>
|
|
<span class=identifier>Allocator</span>
|
|
<span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
In the default case where <code>Compare=std::less<Key></code> and
|
|
<code>Allocator=std::allocator<Key></code>, the substitution rule is
|
|
simplified as
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>set</span><span class=special><</span><span class=identifier>Key</span><span class=special>></span> <span class=special>-></span> <span class=identifier>multi_index_container</span><span class=special><</span><span class=identifier>Key</span><span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The substitution of <code>multi_index_container</code> for <code>std::set</code> keeps
|
|
the whole set of functionality provided by <code>std::set</code>, so in
|
|
principle it is a drop-in replacement needing no further adjustments.
|
|
</p>
|
|
|
|
<p>
|
|
<code>std::multiset</code> can be simulated in a similar manner, according to the
|
|
following rule:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Key</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=identifier>Key</span><span class=special>>,</span><span class=identifier>Compare</span><span class=special>></span> <span class=special>>,</span>
|
|
<span class=identifier>Allocator</span>
|
|
<span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
When default values are taken into consideration, the rule takes the form
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multiset</span><span class=special><</span><span class=identifier>Key</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Key</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=identifier>Key</span><span class=special>></span> <span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The simulation of <code>std::multiset</code>s with <code>multi_index_container</code>
|
|
results in a slight difference with respect to the interface offered: the member
|
|
function <code>insert(const value_type&)</code> does not return an
|
|
<code>iterator</code> as in <code>std::multiset</code>s, but rather a
|
|
<code>std::pair<iterator,bool></code> in the spirit of <code>std::set</code>s.
|
|
In this particular case, however, the <code>bool</code> member of the returned
|
|
pair is always <code>true</code>.
|
|
</p>
|
|
|
|
<p>
|
|
The case of <code>std::map</code>s and <code>std::multimap</code>s does not lend
|
|
itself to such a direct simulation by means of <code>multi_index_container</code>. The main
|
|
problem lies in the fact that elements of a <code>multi_index_container</code> are treated
|
|
as constant, while the <code>std::map</code> and <code>std::multimap</code> handle
|
|
objects of type <code>std::pair<const Key,T></code>, thus allowing for free
|
|
modification of the value part. To overcome this difficulty we need to create an ad
|
|
hoc pair class:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>template</span> <span class=special><</span><span class=keyword>typename</span> <span class=identifier>T1</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>T2</span><span class=special>></span>
|
|
<span class=keyword>struct</span> <span class=identifier>mutable_pair</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>T1</span> <span class=identifier>first_type</span><span class=special>;</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>T2</span> <span class=identifier>second_type</span><span class=special>;</span>
|
|
|
|
<span class=identifier>mutable_pair</span><span class=special>():</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>T1</span><span class=special>()),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>T2</span><span class=special>()){}</span>
|
|
<span class=identifier>mutable_pair</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T1</span><span class=special>&</span> <span class=identifier>f</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>T2</span><span class=special>&</span> <span class=identifier>s</span><span class=special>):</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>f</span><span class=special>),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>s</span><span class=special>){}</span>
|
|
<span class=identifier>mutable_pair</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>T1</span><span class=special>,</span><span class=identifier>T2</span><span class=special>>&</span> <span class=identifier>p</span><span class=special>):</span><span class=identifier>first</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>),</span><span class=identifier>second</span><span class=special>(</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>second</span><span class=special>){}</span>
|
|
|
|
<span class=identifier>T1</span> <span class=identifier>first</span><span class=special>;</span>
|
|
<span class=keyword>mutable</span> <span class=identifier>T2</span> <span class=identifier>second</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
and so the substitution rules are:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>map</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Element</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>>,</span><span class=identifier>Compare</span><span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special><</span><span class=identifier>Element</span><span class=special>>::</span><span class=identifier>other</span>
|
|
<span class=special>></span>
|
|
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multimap</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Compare</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Element</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>>,</span><span class=identifier>Compare</span><span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special><</span><span class=identifier>Element</span><span class=special>>::</span><span class=identifier>other</span>
|
|
<span class=special>></span>
|
|
|
|
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_pair</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>></span>)
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
If default values are considered, the rules take the form:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>map</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Element</span><span class=special>,
|
|
</span><span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>></span> <span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span>
|
|
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>multimap</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Element</span><span class=special>,
|
|
</span><span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>member</span><span class=special><</span><span class=identifier>Element</span><span class=special>,</span><span class=identifier>Key</span><span class=special>,&</span><span class=identifier>Element</span><span class=special>::</span><span class=identifier>first</span><span class=special>></span> <span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span>
|
|
|
|
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_pair</span><span class=special><</span><span class=identifier>Key</span><span class=special>,</span><span class=identifier>T</span><span class=special>></span>)
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Unlike as with standard sets, the interface of these <code>multi_index_container</code>-simulated
|
|
maps does not exactly conform to that of <code>std::map</code>s and
|
|
<code>std::multimap</code>s. The most obvious difference is the lack of
|
|
<code>operator []</code>, either in read or write mode; this, however, can be
|
|
simulated with appropriate use of <code>find</code> and <code>insert</code>.
|
|
</p>
|
|
|
|
<p>
|
|
These simulations of standard associative containers with <code>multi_index_container</code>
|
|
are comparable to the original constructs in terms of space and time efficiency.
|
|
See the <a href="performance.html">performance section</a> for further details.
|
|
</p>
|
|
|
|
<h3><a name="simulate_std_list">Simulation of <code>std::list</code></a></h3>
|
|
|
|
<p>
|
|
Unlike the case of associative containers, simulating <code>std::list</code>
|
|
in Boost.MultiIndex does not add any significant functionality, so the following
|
|
is presented merely for completeness sake.
|
|
</p>
|
|
|
|
<p>
|
|
Much as with standard maps, the main difficulty to overcome when simulating
|
|
<code>std::list</code> derives from the constant nature of elements of an
|
|
<code>multi_index_container</code>. Again, some sort of adaption class is needed, like
|
|
for instance the following:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>template</span> <span class=special><</span><span class=keyword>typename</span> <span class=identifier>T</span><span class=special>></span>
|
|
<span class=keyword>struct</span> <span class=identifier>mutable_value</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>mutable_value</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T</span><span class=special>&</span> <span class=identifier>t</span><span class=special>):</span><span class=identifier>t</span><span class=special>(</span><span class=identifier>t</span><span class=special>){}</span>
|
|
<span class=keyword>operator</span> <span class=identifier>T</span><span class=special>&()</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>t</span><span class=special>;}</span>
|
|
|
|
<span class=keyword>private</span><span class=special>:</span>
|
|
<span class=keyword>mutable</span> <span class=identifier>T</span> <span class=identifier>t</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
which allows us to use the substitution rule:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>list</span><span class=special><</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>Element</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>sequenced</span><span class=special><></span> <span class=special>>,</span>
|
|
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>::</span><span class=keyword>template</span> <span class=identifier>rebind</span><span class=special><</span><span class=identifier>Element</span><span class=special>>::</span><span class=identifier>other</span>
|
|
<span class=special>></span>
|
|
|
|
(<span class=identifier>with</span> <span class=identifier>Element</span><span class=special>=</span><span class=identifier>mutable_value</span><span class=special><</span><span class=identifier>T</span><span class=special>></span>)
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
or, if the default value <code>Allocator=std::allocator<T></code> is used:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>list</span><span class=special><</span><span class=identifier>T</span><span class=special>></span> <span class=special>-></span>
|
|
<span class=identifier>multi_index_container</span><span class=special><</span><span class=identifier>mutable_value</span><span class=special><</span><span class=identifier>T</span><span class=special>>,</span><span class=identifier>indexed_by</span><span class=special><</span><span class=identifier>sequenced</span><span class=special><></span> <span class=special>></span> <span class=special>></span>
|
|
</pre></blockquote>
|
|
|
|
<h2><a name="metaprogrammming">Metaprogramming and <code>multi_index_container</code></a></h2>
|
|
|
|
<p>
|
|
Boost.MultiIndex provides a number of facilities intended to allow the analysis and
|
|
synthesis of <code>multi_index_container</code> instantiations by
|
|
<a href="../../../libs/mpl/doc/index.html">MPL</a> metaprograms.
|
|
</p>
|
|
|
|
<h3><a name="mpl_analysis">MPL analysis</a></h3>
|
|
|
|
<p>
|
|
Given a <code>multi_index_container</code> instantiation, the following nested types are
|
|
provided for compile-time inspection of the various types occurring in the
|
|
definition of the <code>multi_index_container</code>:
|
|
<ul>
|
|
<li><code>index_specifier_type_list</code>,</li>
|
|
<li><code>index_type_list</code>,</li>
|
|
<li><code>iterator_type_list</code>,</li>
|
|
<li><code>const_iterator_type_list</code>.</li>
|
|
</ul>
|
|
Each of these types is a <a href="../../../libs/mpl/doc/ref/Forward_Sequence.html">
|
|
<code>MPL Forward Sequence</code></a> with as many elements as indices
|
|
comprise the <code>multi_index_container</code>: for instance, the <code>n</code>-nth
|
|
element of <code>iterator_type_list</code> is the same as
|
|
<code>nth_index_iterator<n>::type</code>.
|
|
</p>
|
|
|
|
<p>
|
|
A subtle but important distinction exists between
|
|
<code>index_specifier_type_list</code> and <code>index_type_list</code>:
|
|
the former typelist holds the index <i>specifiers</i>
|
|
with which the <code>multi_index_container</code> instantiation was defined,
|
|
while the latter gives access to the actual implementation classes
|
|
corresponding to each specifier. An example will help to clarify
|
|
this distinction. Given the instantiation:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=keyword>int</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>>,</span>
|
|
<span class=identifier>sequenced</span><span class=special><></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>indexed_t</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
<code>indexed_t::index_specifier_type_list</code> is a type list with
|
|
elements
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>></span>
|
|
<span class=identifier>sequenced</span><span class=special><></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
while <code>indexed_t::index_type_list</code> holds the types
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>multi_index_container</span><span class=special>::</span><span class=identifier>nth_type</span><span class=special><</span><span class=number>0</span><span class=special>>::</span><span class=identifier>type</span>
|
|
<span class=identifier>multi_index_container</span><span class=special>::</span><span class=identifier>nth_type</span><span class=special><</span><span class=number>1</span><span class=special>>::</span><span class=identifier>type</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
so the typelists are radically different.
|
|
</p>
|
|
|
|
<h3><a name="mpl_synthesis">MPL synthesis</a></h3>
|
|
|
|
<p>
|
|
Although typically indices are specified by means of the
|
|
<code>indexed_by</code> construct, actually any MPL sequence of
|
|
index specifiers can be provided instead:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>typedef</span> <span class=identifier>mpl</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>>,</span><span class=identifier>sequenced</span><span class=special><></span> <span class=special>></span> <span class=identifier>index_list_t</span><span class=special>;</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=keyword>int</span><span class=special>,</span>
|
|
<span class=identifier>index_list_t</span>
|
|
<span class=special>></span> <span class=identifier>indexed_t</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
This possibility enables the synthesis of instantiations of
|
|
<code>multi_index_container</code> through MPL metaprograms, as the following
|
|
example shows:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// original multi_index_container instantiation</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=keyword>int</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>indexed_t1</span><span class=special>;</span>
|
|
|
|
<span class=comment>// we take its index list and add an index</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>push_front</span><span class=special><</span>
|
|
<span class=identifier>indexed_t1</span><span class=special>::</span><span class=identifier>index_specifier_type_list</span><span class=special>,</span>
|
|
<span class=identifier>sequenced</span><span class=special><></span>
|
|
<span class=special>>::</span><span class=identifier>type</span> <span class=identifier>index_list_t</span><span class=special>;</span>
|
|
|
|
<span class=comment>// augmented multi_index_container</span>
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=keyword>int</span><span class=special>,</span>
|
|
<span class=identifier>index_list_t</span>
|
|
<span class=special>></span> <span class=identifier>indexed_t2</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<hr>
|
|
|
|
<div class="prev_link"><a href="tutorial.html"><img src="prev.gif" alt="tutorial" border="0"><br>
|
|
Tutorial
|
|
</a></div>
|
|
<div class="up_link"><a href="index.html"><img src="up.gif" alt="index" border="0"><br>
|
|
Index
|
|
</a></div>
|
|
<div class="next_link"><a href="reference/index.html"><img src="next.gif" alt="reference" border="0"><br>
|
|
Reference
|
|
</a></div><br clear="all" style="clear: all;">
|
|
|
|
<br>
|
|
|
|
<p>Revised May 7th 2004</p>
|
|
|
|
<p>Copyright © 2003-2004 Joaquín M López Muñoz.
|
|
Use, modification, and distribution are subject to the Boost Software
|
|
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
|
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
|
www.boost.org/LICENSE_1_0.txt</a>)
|
|
</p>
|
|
|
|
</body>
|
|
</html>
|