mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-12 05:41:47 +00:00
1590 lines
107 KiB
HTML
1590 lines
107 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="../../../boost.png" alt="boost.png (6897 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="#hashed_indices">Hashed indices</a>
|
|
<ul>
|
|
<li><a href="#hash_unique_non_unique">Unique and non-unique variants</a></li>
|
|
<li><a href="#hash_spec">Specification</a></li>
|
|
<li><a href="#hash_lookup">Lookup</a></li>
|
|
<li><a href="#hash_updating">Updating</a></li>
|
|
<li><a href="#guarantees">Guarantees on iterator validity and exception safety</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#composite_keys">Composite keys</a>
|
|
<ul>
|
|
<li><a href="#composite_keys_hash">Composite keys and hashed indices</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#advanced_key_extractors">Advanced features of Boost.MultiIndex key
|
|
extractors</a></li>
|
|
<li><a href="#ctor_args_list">Use of <code>ctor_args_list</code></a></li>
|
|
<li><a href="#serialization">Serialization</a></li>
|
|
<li><a href="#debugging_support">Debugging support</a>
|
|
<ul>
|
|
<li><a href="#safe_mode">Safe mode</a>
|
|
<ul>
|
|
<li><a href="#serialization_and_safe_mode">Serialization and safe mode</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#invariant_check">Invariant-checking mode</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#emulate_std_containers">Emulating standard containers with
|
|
<code>multi_index_container</code></a>
|
|
<ul>
|
|
<li><a href="#emulate_assoc_containers">Emulation of associative
|
|
containers</a></li>
|
|
<li><a href="#emulate_std_list">Emulation 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="hashed_indices">Hashed indices</a></h2>
|
|
|
|
<p>
|
|
Hashed indices constitute a trade-off with respect to ordered indices: if correctly used,
|
|
they provide much faster lookup of elements, at the expense of losing sorting
|
|
information.
|
|
Let us revisit our <code>employee_set</code> example: suppose a field for storing
|
|
the Social Security number is added, with the requisite that lookup by this
|
|
number should be as fast as possible. Instead of the usual ordered index, a
|
|
hashed index can be resorted to:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>employee</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>int</span> <span class=identifier>id</span><span class=special>;</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>ssnumber</span><span class=special>;</span>
|
|
|
|
<span class=identifier>employee</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>id</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=identifier>name</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>ssnumber</span><span class=special>):</span>
|
|
<span class=identifier>id</span><span class=special>(</span><span class=identifier>id</span><span class=special>),</span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</span><span class=special>),</span><span class=identifier>ssnumber</span><span class=special>(</span><span class=identifier>ssnumber</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>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>id</span><span class=special><</span><span class=identifier>e</span><span class=special>.</span><span class=identifier>id</span><span class=special>;}</span>
|
|
<span class=special>};</span>
|
|
|
|
<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=comment>// sort by employee::operator<</span>
|
|
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=identifier>employee</span><span class=special>></span> <span class=special>>,</span>
|
|
|
|
<span class=comment>// sort by less<string> on name</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=comment>// hashed on ssnumber</span>
|
|
<span class=identifier>hashed_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=keyword>int</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>></span> <span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>></span> <span class=identifier>employee_set</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Note that the hashed index does not guarantee any particular ordering of the
|
|
elements: so, for instance, we cannot efficiently query the employees whose SSN is
|
|
greater than a given number. Usually, you must consider these restrictions when
|
|
determining whether a hashed index is preferred over an ordered one.
|
|
</p>
|
|
|
|
<p>
|
|
If you are familiar with non-standard <code>hash_set</code>s provided
|
|
by some compiler vendors, then learning to use hashed indices should be straightforward.
|
|
However, the interface of hashed indices is modeled after the specification
|
|
for unordered associative containers by the
|
|
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1836.pdf">C++ Standard
|
|
Library Technical Report</a> (TR1),
|
|
which differs in some significant aspects from existing pre-standard
|
|
implementations:
|
|
<ul>
|
|
<li>As there is no notion of ordering between keys, the <a href="#hash_lookup">lookup
|
|
interface</a> does not offer <code>lower_bound</code> or <code>upper_bound</code>
|
|
member functions (unlike Dinkumware's solution.)</li>
|
|
<li>A set of member functions is provided for handling the internal
|
|
bucket structure on which hashed indices rely. This includes facilities
|
|
for <a href="reference/hash_indices.html#hash_policy">rehashing</a>,
|
|
control of the load factor (number of elements divided by number of buckets),
|
|
and inspection of the buckets contents. Pre-standard implementations
|
|
do not have such an extensive functionality.</li>
|
|
</ul>
|
|
Check the <a href="reference/hash_indices.html">reference</a> for a
|
|
complete specification of the interface of hashed indices,
|
|
and <a href="examples.html#example8">example 8</a> and
|
|
<a href="examples.html#example9">example 9</a> for practical applications.
|
|
</p>
|
|
|
|
</p>
|
|
|
|
<h3><a name="hash_unique_non_unique">Unique and non-unique variants</a></h3>
|
|
|
|
<p>
|
|
Just like ordered indices, hashed indices have unique and non-unique variants, selected
|
|
with the specifiers <code>hashed_unique</code> and <code>hashed_non_unique</code>,
|
|
respectively. In the latter case, elements with equivalent keys are kept together and can
|
|
be jointly retrieved by means of the <code>equal_range</code> member function.
|
|
</p>
|
|
|
|
<h3><a name="hash_spec">Specification</a></h3>
|
|
|
|
<p>
|
|
Hashed indices specifiers have two alternative syntaxes, depending on whether
|
|
<a href="tutorial.html#tagging">tags</a> are provided or not:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=special>(</span><span class=identifier>hashed_unique</span> <span class=special>|</span> <span class=identifier>hashed_non_unique</span><span class=special>)
|
|
</span><span class=special><[</span><i>(tag)</i><span class=special>[,</span><i>(key extractor)</i><span class=special>[,</span><i>(hash function)</i><span class=special>[,</span><i>(equality predicate)</i><span class=special>]]]]></span>
|
|
|
|
<span class=special>(</span><span class=identifier>hashed_unique</span> <span class=special>|</span> <span class=identifier>hashed_non_unique</span><span class=special>)</span>
|
|
<span class=special><[</span><i>(key extractor)</i><span class=special>[,</span><i>(hash function)</i><span class=special>[,</span><i>(equality predicate)</i><span class=special>]]]></span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The key extractor parameter works in exactly the same way as for
|
|
<a href="tutorial.html#key_extraction">ordered indices</a>; lookup, insertion,
|
|
etc., are based on the key returned by the extractor rather than the whole
|
|
element.
|
|
</p>
|
|
|
|
<p>
|
|
The hash function is the very core of the fast lookup capabilities of this type of
|
|
indices: a hasher
|
|
is just a <a href="http://www.sgi.com/tech/stl/UnaryFunction.html"><code>Unary
|
|
Function</code></a> returning an <code>std::size_t</code> value for any given
|
|
key. In general, it is impossible that every key map to a different hash value, for
|
|
the space of keys can be greater than the number of permissible hash codes: what
|
|
makes for a good hasher is that the probability of a collision (two different
|
|
keys with the same hash value) is as close to zero as possible. This is a statistical
|
|
property depending on the typical distribution of keys in a given application, so
|
|
it is not feasible to have a general-purpose hash function with excellent results
|
|
in <i>every</i> possible scenario; the default value for this parameter uses
|
|
<a href="../../functional/hash/index.html">Boost.Hash</a>, which often provides good
|
|
enough results.
|
|
</p>
|
|
|
|
<p>
|
|
The equality predicate is used to determine whether two keys are to be treated
|
|
as the same. The default
|
|
value <code>std::equal_to<KeyFromValue::result_type></code> is in most
|
|
cases exactly what is needed, so very rarely will you have to provide
|
|
your own predicate. Note that hashed indices require that two
|
|
equivalent keys have the same hash value, which
|
|
in practice greatly reduces the freedom in choosing an equality predicate.
|
|
</p>
|
|
|
|
<h3><a name="hash_lookup">Lookup</a></h3>
|
|
|
|
<p>
|
|
The lookup interface of hashed indices consists in member functions
|
|
<code>find</code>, <code>count</code> and <code>equal_range</code>.
|
|
Note that <code>lower_bound</code> and <code>upper_bound</code> are not
|
|
provided, as there is no intrinsic ordering of keys in this type of indices.
|
|
</p>
|
|
|
|
<p>
|
|
Just as with ordered indices, these member functions take keys
|
|
as their search arguments, rather than entire objects. Remember that
|
|
ordered indices lookup operations are further augmented to accept
|
|
<i>compatible keys</i>, which can roughly be regarded as "subkeys".
|
|
For hashed indices, a concept of
|
|
<a href="reference/hash_indices.html#lookup">compatible key</a> is also
|
|
supported, though its usefulness is much more limited: basically,
|
|
a compatible key is an object which is entirely equivalent to
|
|
a native object of <code>key_type</code> value, though maybe with
|
|
a different internal representation:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// US SSN numbering scheme</span>
|
|
<span class=keyword>struct</span> <span class=identifier>ssn</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>ssn</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>area_no</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>group_no</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>serial_no</span><span class=special>):</span>
|
|
<span class=identifier>area_no</span><span class=special>(</span><span class=identifier>area_no</span><span class=special>),</span><span class=identifier>group_no</span><span class=special>(</span><span class=identifier>group_no</span><span class=special>),</span><span class=identifier>serial_no</span><span class=special>(</span><span class=identifier>serial_no</span><span class=special>)</span>
|
|
<span class=special>{}</span>
|
|
|
|
<span class=keyword>int</span> <span class=identifier>to_int</span><span class=special>()</span><span class=keyword>const</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>return</span> <span class=identifier>serial_no</span><span class=special>+</span><span class=number>10000</span><span class=special>*</span><span class=identifier>group_no</span><span class=special>+</span><span class=number>1000000</span><span class=special>*</span><span class=identifier>area_no</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=keyword>private</span><span class=special>:</span>
|
|
<span class=keyword>int</span> <span class=identifier>area_no</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>group_no</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>serial_no</span><span class=special>;</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=comment>// interoperability with SSNs in raw int form</span>
|
|
|
|
<span class=keyword>struct</span> <span class=identifier>ssn_equal</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>ssn</span><span class=special>&</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</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=identifier>x</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>()==</span><span class=identifier>y</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>ssn</span><span class=special>&</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=identifier>x</span><span class=special>==</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>();</span>
|
|
<span class=special>}</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=keyword>struct</span> <span class=identifier>ssn_hash</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>ssn</span><span class=special>&</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>return</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special><</span><span class=keyword>int</span><span class=special>>()(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>to_int</span><span class=special>());</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>return</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special><</span><span class=keyword>int</span><span class=special>>()(</span><span class=identifier>x</span><span class=special>);</span>
|
|
<span class=special>}</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>employee_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=identifier>employee_set_by_ssn</span><span class=special>;</span>
|
|
|
|
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
|
|
<span class=identifier>employee_set_by_ssn</span><span class=special>&</span> <span class=identifier>ssn_index</span><span class=special>=</span><span class=identifier>es</span><span class=special>.</span><span class=identifier>get</span><span class=special><</span><span class=number>2</span><span class=special>>();</span>
|
|
<span class=special>...</span>
|
|
<span class=comment>// find an employee by ssn</span>
|
|
<span class=identifier>employee</span> <span class=identifier>e</span><span class=special>=*(</span><span class=identifier>ssn_index</span><span class=special>.</span><span class=identifier>find</span><span class=special>(</span><span class=identifier>ssn</span><span class=special>(</span><span class=number>12</span><span class=special>,</span><span class=number>1005</span><span class=special>,</span><span class=number>20678</span><span class=special>),</span><span class=identifier>ssn_hash</span><span class=special>(),</span><span class=identifier>ssn_equal</span><span class=special>()));</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
In the example, we provided a hash functor <code>ssn_hash</code> and an
|
|
equality predicate <code>ssn_equal</code> allowing for interoperability
|
|
between <code>ssn</code> objects and the raw <code>int</code>s stored as
|
|
<code>SSN</code>s in <code>employee_set</code>.
|
|
</p>
|
|
|
|
<p>
|
|
By far, the most useful application of compatible keys in the context
|
|
of hashed indices lies in the fact that they allow for seamless usage of
|
|
<a href="#composite_keys">composite keys</a>.
|
|
</p>
|
|
|
|
<h3><a name="hash_updating">Updating</a></h3>
|
|
|
|
<p>
|
|
Hashed indices have
|
|
<a href=reference/hash_indices.html#replace><code>replace</code></a>,
|
|
<a href=reference/hash_indices.html#modify><code>modify</code></a> and
|
|
<a href=reference/hash_indices.html#modify_key><code>modify_key</code></a>
|
|
member functions, with the same functionality as in ordered indices.
|
|
</p>
|
|
|
|
<h3><a name="guarantees">Guarantees on iterator validity and exception safety</a></h3>
|
|
|
|
<p>
|
|
Due to the internal constraints imposed by the Boost.MultiIndex framework,
|
|
hashed indices provide guarantees on iterator validity and
|
|
exception safety that are actually stronger than required by the
|
|
C++ Standard Library Technical Report (TR1) with respect
|
|
to unordered associative containers:
|
|
<ul>
|
|
<li>Iterator validity is preserved in any case during insertion or rehashing:
|
|
TR1 allows for iterator invalidation when a rehash (implicit or explicit)
|
|
is performed.</li>
|
|
<li>Erasing an element or range of elements via iterators does not throw ever,
|
|
as the internal hash function and equality predicate objects are not actually
|
|
invoked.</li>
|
|
<li><code>rehash</code> provides the strong exception safety guarantee
|
|
unconditionally. TR1 only warrants it if the internal hash function and
|
|
equality predicate objects do not throw. The somewhat surprising consequence
|
|
is that a TR1-compliant unordered associative container might erase
|
|
elements if an exception is thrown during rehashing!</li>
|
|
</ul>
|
|
In general, these stronger guarantees play in favor of the user's convenience,
|
|
specially that which refers to iterator stability. A (hopefully minimal)
|
|
degradation in performance might result in exchange for these commodities,
|
|
though.
|
|
</p>
|
|
|
|
<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>
|
|
|
|
<h3><a name="composite_keys_hash">Composite keys and hashed indices</a></h3>
|
|
|
|
<p>
|
|
Composite keys can also be used with hashed indices in a straightforward manner:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>street_entry</span>
|
|
<span class=special>{</span>
|
|
<span class=comment>// quadrant coordinates</span>
|
|
<span class=keyword>int</span> <span class=identifier>x</span><span class=special>;</span>
|
|
<span class=keyword>int</span> <span class=identifier>y</span><span class=special>;</span>
|
|
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
|
|
|
|
<span class=identifier>street_entry</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>y</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=identifier>name</span><span class=special>):</span><span class=identifier>x</span><span class=special>(</span><span class=identifier>x</span><span class=special>),</span><span class=identifier>y</span><span class=special>(</span><span class=identifier>y</span><span class=special>),</span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</span><span class=special>){}</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>street_entry</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by quadrant coordinates</span>
|
|
<span class=identifier>composite_key</span><span class=special><</span>
|
|
<span class=identifier>street_entry</span><span class=special>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>></span>
|
|
<span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by street name</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_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>street_entry</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>street_locator</span><span class=special>;</span>
|
|
|
|
<span class=identifier>street_locator</span> <span class=identifier>sl</span><span class=special>;</span>
|
|
<span class=special>...</span>
|
|
<span class=keyword>void</span> <span class=identifier>streets_in_quadrant</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>y</span><span class=special>)</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>street_locator</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>sl</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>x</span><span class=special>,</span><span class=identifier>y</span><span class=special>));</span>
|
|
|
|
<span class=keyword>while</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>second</span><span class=special>){</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</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>name</span><span class=special><<</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;</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=special>}</span>
|
|
<span class=special>}</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Note that hashing is automatically taken care of: <code>boost::hash</code> is
|
|
specialized to hash a composite key as a function of the <code>boost::hash</code>
|
|
values of its elements. Should we need to specify different hash functions for the
|
|
elements of a composite key, we can explicitly do so by using the
|
|
<a href="reference/key_extraction.html#composite_key_hash"><code>composite_key_hash</code></a>
|
|
utility:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=keyword>struct</span> <span class=identifier>tuned_int_hash</span>
|
|
<span class=special>{</span>
|
|
<span class=keyword>int</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>int</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
|
|
<span class=special>{</span>
|
|
<span class=comment>// specially tuned hash for this application</span>
|
|
<span class=special>}</span>
|
|
<span class=special>};</span>
|
|
|
|
<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span>
|
|
<span class=identifier>street_entry</span><span class=special>,</span>
|
|
<span class=identifier>indexed_by</span><span class=special><</span>
|
|
<span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by quadrant coordinates</span>
|
|
<span class=identifier>composite_key</span><span class=special><</span>
|
|
<span class=identifier>street_entry</span><span class=special>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>>,</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>composite_key_hash</span><span class=special><</span>
|
|
<span class=identifier>tuned_int_hash</span><span class=special>,</span>
|
|
<span class=identifier>tuned_int_hash</span>
|
|
<span class=special>></span>
|
|
<span class=special>>,</span>
|
|
<span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by street name</span>
|
|
<span class=identifier>member</span><span class=special><</span><span class=identifier>street_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>street_entry</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>street_locator</span><span class=special>;</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Also, equality of composite keys can be tuned with
|
|
<a href="reference/key_extraction.html#composite_key_equal_to"><code>composite_key_equal_to</code></a>,
|
|
though in most cases the default equality predicate (relying on
|
|
the <code>std::equal_to</code> instantiations for the element types)
|
|
will be the right choice.
|
|
</p>
|
|
|
|
<p>
|
|
Unlike with ordered indices, we cannot perform partial searches specifying
|
|
only the first elements of a composite key:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=comment>// try to locate streets in quadrants with x==0
|
|
// compile-time error: hashed indices do not allow such operations</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>street_locator</span><span class=special>::</span><span class=identifier>iterator</span><span class=special>,</span><span class=identifier>street_locator</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>sl</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=number>0</span><span class=special>));</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The reason for this limitation is quite logical: as the hash value of a composite
|
|
key depends on all of its elements, it is impossible to calculate it from
|
|
partial information.
|
|
</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> key </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>
|
|
|
|
<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, hashed indices take an initial number of buckets,
|
|
a key extractor, a hash function and an equality 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>hashed_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>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,</span> <span class=comment>// initial number of buckets; 0 if unspecified</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>boost</span><span class=special>::</span><span class=identifier>hash</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>equal_to</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="serialization">Serialization</a></h2>
|
|
|
|
<p>
|
|
<code>multi_index_container</code>s can be archived and retrieved by means of the
|
|
<a href="../../serialization/index.html">Boost Serialization Library</a>. Both regular
|
|
and XML archives are supported. The usage is straightforward and does not
|
|
differ from any other serializable type. For instance:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>archive</span><span class=special>/</span><span class=identifier>text_oarchive</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>boost</span><span class=special>/</span><span class=identifier>archive</span><span class=special>/</span><span class=identifier>text_iarchive</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>fstream</span><span class=special>></span>
|
|
|
|
<span class=special>...</span>
|
|
|
|
<span class=keyword>void</span> <span class=identifier>save</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>employee_set</span><span class=special>&</span> <span class=identifier>es</span><span class=special>)</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>ofstream</span> <span class=identifier>ofs</span><span class=special>(</span><span class=string>"data"</span><span class=special>);</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>archive</span><span class=special>::</span><span class=identifier>text_oarchive</span> <span class=identifier>oa</span><span class=special>(</span><span class=identifier>ofs</span><span class=special>);</span>
|
|
<span class=identifier>oa</span><span class=special><<</span><span class=identifier>es</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=keyword>void</span> <span class=identifier>load</span><span class=special>(</span><span class=identifier>employee_set</span><span class=special>&</span> <span class=identifier>es</span><span class=special>)</span>
|
|
<span class=special>{</span>
|
|
<span class=identifier>std</span><span class=special>::</span><span class=identifier>ifstream</span> <span class=identifier>ifs</span><span class=special>(</span><span class=string>"data"</span><span class=special>);</span>
|
|
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>archive</span><span class=special>::</span><span class=identifier>text_iarchive</span> <span class=identifier>ia</span><span class=special>(</span><span class=identifier>ifs</span><span class=special>);</span>
|
|
<span class=identifier>ia</span><span class=special>>></span><span class=identifier>es</span><span class=special>;</span>
|
|
<span class=special>}</span>
|
|
|
|
<span class=special>...</span>
|
|
|
|
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
|
|
<span class=special>...</span> <span class=comment>// fill it with data</span>
|
|
<span class=identifier>save</span><span class=special>(</span><span class=identifier>es</span><span class=special>);</span>
|
|
|
|
<span class=special>...</span>
|
|
|
|
<span class=identifier>employee_set</span> <span class=identifier>restored_es</span><span class=special>;</span>
|
|
<span class=identifier>load</span><span class=special>(</span><span class=identifier>restored_es</span><span class=special>);</span>
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Serialization capabilities are automatically provided by just linking with
|
|
the appropriate Boost.Serialization library module: it is not necessary
|
|
to explicitly include any header from Boost.Serialization,
|
|
apart from those declaring the type of archive used in the process. If not used,
|
|
however, serialization support can be disabled by globally defining the macro
|
|
<code>BOOST_MULTI_INDEX_DISABLE_SERIALIZATION</code>. Disabling serialization
|
|
for Boost.MultiIndex can yield a small improvement in build times, and may
|
|
be necessary in those defective compilers that fail to correctly process
|
|
Boost.Serialization headers.
|
|
</p>
|
|
|
|
<p>
|
|
When retrieving an archived <code>multi_index_container</code>, not only
|
|
the elements are restored, but also the order they were arranged into for
|
|
every index of the container. This is specially important with sequenced
|
|
indices, whose ordering is not automatically fixed, as happens for
|
|
ordered unique indices. Ordered <i>non-unique</i> indices are an in-between
|
|
case: elements with different keys are sorted in ascending order, but
|
|
there is no implicit traversal order for elements with the same key.
|
|
Serialization of <code>multi_index_container</code> addresses this issue,
|
|
so that restored ordered non-unique indices are sorted in exactly the
|
|
same way as their originals. As for hashed indices, no guarantee is made
|
|
about the order in which elements will be iterated in the restored
|
|
container: in general, it is unwise to rely on the ordering of elements
|
|
of a hashed index, since it can change in arbitrary ways during
|
|
insertion or rehashing.
|
|
</p>
|
|
|
|
<p>
|
|
Iterators to indices of a <code>multi_index_container</code> can also be
|
|
serialized. Serialization of iterators must be done only after serializing
|
|
its corresponding container.
|
|
</p>
|
|
|
|
<p>
|
|
<a href="examples.html#example9">Example 9</a> in the examples section shows
|
|
the serialization capabilities of Boost.MultiIndex.
|
|
</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.</li>
|
|
</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>// vg. default cted or pointing to erased element</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>
|
|
|
|
<h4><a name="serialization_and_safe_mode">Serialization and safe mode</a></h4>
|
|
|
|
<p>
|
|
Iterators restored from an archive are not subject to safe mode checks. This is
|
|
so because it is not possible to automatically know the associated
|
|
<code>multi_index_container</code> of an iterator from the serialization
|
|
information alone. However, if desired, a restored iterator can be converted to a
|
|
checked value by using the following workaround:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<span class=identifier>employee_set</span> <span class=identifier>es</span><span class=special>;</span>
|
|
<span class=identifier>employee_set</span><span class=special>::</span><span class=identifier>nth_index</span><span class=special><</span><span class=number>1</span><span class=special>>::</span><span class=identifier>iterator</span> <span class=identifier>it</span><span class=special>;</span>
|
|
|
|
<span class=comment>// restore es and it from an archive ar</span>
|
|
<span class=identifier>ar</span><span class=special>>></span><span class=identifier>es</span><span class=special>;</span>
|
|
<span class=identifier>ar</span><span class=special>>></span><span class=identifier>it</span><span class=special>;</span> <span class=comment>// it won't benefit from safe mode checks
|
|
|
|
// turn it into a checked value by providing
|
|
// Boost.MultiIndex with info about the associated container</span>
|
|
<span class=identifier>it</span><span class=special>=</span><span class=identifier>es</span><span class=special>.</span><span class=identifier>project</span><span class=special><</span><span class=number>1</span><span class=special>>(</span><span class=identifier>it</span><span class=special>);</span>
|
|
</pre></blockquote>
|
|
|
|
<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="emulate_std_containers">Emulating standard containers with
|
|
<code>multi_index_container</code></a></h2>
|
|
|
|
<h3><a name="emulate_assoc_containers">Emulation of associative
|
|
containers</a></h3>
|
|
|
|
<p>
|
|
Academic movitations aside, there is a practical interest in emulating 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 emulate 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 emulated 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 emulation 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 emulation 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>-emulated
|
|
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
|
|
emulated with appropriate use of <code>find</code> and <code>insert</code>.
|
|
</p>
|
|
|
|
<p>
|
|
These emulations 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="emulate_std_list">Emulation of <code>std::list</code></a></h3>
|
|
|
|
<p>
|
|
Unlike the case of associative containers, emulating <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 emulating
|
|
<code>std::list</code> derives from the constant nature of elements of a
|
|
<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 an MPL sequence with as many elements as indices
|
|
comprise the <code>multi_index_container</code>: for instance, the <code>n</code>-th
|
|
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. Check the
|
|
<a href="reference/multi_index_container.html#types">reference</a>
|
|
for the exact MPL sequence concepts modeled by these type lists.
|
|
</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 August 24th 2005</p>
|
|
|
|
<p>© Copyright 2003-2005 Joaquín M López Muñoz.
|
|
Distributed under 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">
|
|
http://www.boost.org/LICENSE_1_0.txt</a>)
|
|
</p>
|
|
|
|
</body>
|
|
</html>
|