• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
2
3<html>
4<head>
5<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
6<title>Boost.MultiIndex Documentation - Tutorial - Key extraction</title>
7<link rel="stylesheet" href="../style.css" type="text/css">
8<link rel="start" href="../index.html">
9<link rel="prev" href="indices.html">
10<link rel="up" href="index.html">
11<link rel="next" href="creation.html">
12</head>
13
14<body>
15<h1><img src="../../../../boost.png" alt="boost.png (6897 bytes)" align=
16"middle" width="277" height="86">Boost.MultiIndex Tutorial: Key extraction</h1>
17
18<div class="prev_link"><a href="indices.html"><img src="../prev.gif" alt="index types" border="0"><br>
19Index types
20</a></div>
21<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
22Boost.MultiIndex tutorial
23</a></div>
24<div class="next_link"><a href="creation.html"><img src="../next.gif" alt="container creation" border="0"><br>
25Container creation
26</a></div><br clear="all" style="clear: all;">
27
28<hr>
29
30<h2>Contents</h2>
31
32<ul>
33  <li><a href="#intro">Introduction</a>
34    <ul>
35      <li><a href="#read_write_key_extractors">Read/write key extractors</a></li>
36    </ul>
37  </li>
38  <li><a href="#predefined_key_extractors">Predefined key extractors</a>
39    <ul>
40      <li><a href="#identity"><code>identity</code></a></li>
41      <li><a href="#member"><code>member</code></a></li>
42      <li><a href="#const_mem_fun"><code>const_mem_fun</code> and <code>mem_fun</code></a>
43        <ul>
44          <li><a href="#x_mem_fun">Variants for other types of member functions</a></li>
45        </ul>
46      </li>
47      <li><a href="#global_fun"><code>global_fun</code></a></li>
48    </ul>
49  </li>
50  <li><a href="#user_defined_key_extractors">User-defined key extractors</a></li>
51  <li><a href="#composite_keys">Composite keys</a>
52    <ul>
53      <li><a href="#composite_keys_hash">Composite keys and hashed indices</a></li>
54    </ul>
55  </li>
56  <li><a href="#key">C++17 terse key specification syntax</a></li>
57  <li><a href="#advanced_key_extractors">Advanced features of Boost.MultiIndex key
58    extractors</a></li>
59</ul>
60
61<h2><a name="intro">Introduction</a></h2>
62
63<p>
64STL associative containers have a notion of key, albeit in a somewhat incipient
65form. So, the keys of such containers are identified by a nested type
66<code>key_type</code>; for <code>std::set</code>s and <code>std::multiset</code>s,
67<code>key_type</code> coincides with <code>value_type</code>, i.e. the key is the
68element itself. <code>std::map</code> and <code>std::multimap</code> manage
69elements of type <code>std::pair&lt;const Key,T&gt;</code>, where the first
70member is the key. In either case, the process of obtaining the key from a
71given element is implicitly fixed and cannot be customized by the user.
72</p>
73
74<p>
75Fixed key extraction mechanisms like those performed by STL associative
76containers do not scale well in the context of Boost.MultiIndex, where
77several indices share their <code>value_type</code> definition but
78might feature completely different lookup semantics. For this reason,
79Boost.MultiIndex formalizes the concept of a
80<a href="../reference/key_extraction.html#key_extractors"><code>Key
81Extractor</code></a> in order to make it explicit and controllable
82in the definition of key-based indices.
83</p>
84
85<p>
86Intuitively speaking, a key extractor is a function object that accepts
87a reference to an element and returns its associated key. The formal
88concept also imposes some reasonable constraints about the stability
89of the process, in the sense that extractors are assumed to
90return the same key when passed the same element: this is in consonance
91with the informal understanding that keys are actually some "part"
92of the element and do not depend on external data.
93</p>
94
95<h3><a name="read_write_key_extractors">Read/write key extractors</a></h3>
96
97<p>
98A key extractor is called <i>read/write</i> if it returns a non-constant reference
99to the key when passed a non-constant element, and it is called <i>read-only</i>
100otherwise. Boost.MultiIndex requires that the key extractor be read/write
101when using the <code>modify_key</code> member function of key-based
102indices. In all other situations, read-only extractors suffice.
103The section on <a href="#advanced_key_extractors">advanced features
104of Boost.MultiIndex key extractors</a> shows typical situations on which the predefined
105key extractors are read/write.
106</p>
107
108<h2><a name="predefined_key_extractors">Predefined key extractors</a></h2>
109
110<h3><a name="identity"><code>identity</code></a></h3>
111
112<p>
113The <a href="../reference/key_extraction.html#identity"><code>identity</code></a>
114key extractor returns the entire base object as the associated key:
115</p>
116
117<blockquote><pre>
118<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
119<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
120<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
121
122<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
123  <span class=keyword>int</span><span class=special>,</span>
124  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
125    <span class=identifier>ordered_unique</span><span class=special>&lt;</span>
126      <span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=comment>// the key is the entire element</span>
127    <span class=special>&gt;</span>
128  <span class=special>&gt;</span>
129<span class=special>&gt;</span> <span class=identifier>cont</span><span class=special>;</span>
130</pre></blockquote>
131
132<h3><a name="member"><code>member</code></a></h3>
133
134<p>
135<a href="../reference/key_extraction.html#member"><code>member</code></a>
136key extractors return a reference to a specified
137data field of the base object. For instance, in the following version of our
138familiar employee container:
139</p>
140
141<blockquote><pre>
142<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
143<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
144<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
145<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
146
147<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
148  <span class=identifier>employee</span><span class=special>,</span>
149  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
150    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
151    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
152    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>ssnumber</span><span class=special>&gt;</span> <span class=special>&gt;</span>
153  <span class=special>&gt;</span>
154<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
155</pre></blockquote>
156
157<p>
158the second and third indices use <code>member</code> extractors on
159<code>employee::name</code> and <code>employee::ssnumber</code>, respectively.
160The specification of an instantiation of <code>member</code> is simple
161yet a little contrived:
162</p>
163
164<blockquote><pre>
165<span class=identifier>member</span><span class=special>&lt;</span><span class=identifier><i>(base type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to member)</i></span><span class=special>&gt;</span>
166</pre></blockquote>
167
168<p>
169It might seem that the first and second parameters are superfluous,
170since the type of the base object and of the associated data field are
171already implicit in the pointer to member argument: unfortunately, it is
172not possible to extract this information with current C++ mechanisms,
173which makes the syntax of <code>member</code> a little too verbose.
174</p>
175
176<h3><a name="const_mem_fun"><code>const_mem_fun</code> and <code>mem_fun</code></a></h3>
177
178<p>
179Sometimes, the key of an index is not a concrete data member of the element,
180but rather it is a value returned by a particular member function.
181This resembles the notion of <i>calculated indices</i> supported by some
182relational databases. Boost.MultiIndex supports this
183kind of key extraction through
184<a href="../reference/key_extraction.html#const_mem_fun"><code>const_mem_fun</code></a>.
185Consider the following container where sorting on the third index
186is based upon the length of the name field:
187</p>
188
189<blockquote><pre>
190<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
191<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
192<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
193<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
194<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>mem_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
195
196<span class=keyword>struct</span> <span class=identifier>employee</span>
197<span class=special>{</span>
198  <span class=keyword>int</span>         <span class=identifier>id</span><span class=special>;</span>
199  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
200
201  <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>&amp;</span> <span class=identifier>name</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>
202
203  <span class=keyword>bool</span> <span class=keyword>operator</span><span class=special>&lt;(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&amp;</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>&lt;</span><span class=identifier>e</span><span class=special>.</span><span class=identifier>id</span><span class=special>;}</span>
204
205  <span class=comment>// returns the length of the name field</span>
206  <span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>name_length</span><span class=special>()</span><span class=keyword>const</span><span class=special>{</span><span class=keyword>return</span> <span class=identifier>name</span><span class=special>.</span><span class=identifier>size</span><span class=special>();}</span>
207<span class=special>};</span>
208
209<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
210  <span class=identifier>employee</span><span class=special>,</span>
211  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
212    <span class=comment>// sort by employee::operator&lt;</span>
213    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
214
215    <span class=comment>// sort by less&lt;string&gt; on name</span>
216    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
217
218    <span class=comment>// sort by less&lt;int&gt; on name_length()</span>
219    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
220      <span class=identifier>const_mem_fun</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name_length</span><span class=special>&gt;</span>
221    <span class=special>&gt;</span>
222  <span class=special>&gt;</span>
223<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
224</pre></blockquote>
225
226<p>
227<code>const_mem_fun</code> usage syntax is similar to that of
228<a href="#member"><code>member</code></a>:
229</p>
230
231<blockquote><pre>
232<span class=identifier>const_mem_fun</span><span class=special>&lt;</span><span class=identifier><i>(base type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to member function)</i></span><span class=special>&gt;</span>
233</pre></blockquote>
234
235<p>
236The member function referred to must be <code>const</code>, take no arguments and return
237a value of the specified key type.
238Almost always you will want to use a <code>const</code> member function,
239since elements in a <code>multi_index_container</code> are treated as constant, much
240as elements of an <code>std::set</code>. However, a
241<a href="../reference/key_extraction.html#mem_fun"><code>mem_fun</code></a>
242counterpart is provided for use with non-constant member functions, whose
243applicability is discussed on the paragraph on
244<a href="#advanced_key_extractors">advanced features
245of Boost.MultiIndex key extractors</a>.
246</p>
247
248<p><a href="../examples.html#example2">Example 2</a> in the examples section
249provides a complete program showing how to use <code>const_mem_fun</code>.
250<p>
251
252<h4><a name="x_mem_fun">Variants for other types of member functions</a></h4>
253
254<p>
255Consider the following, non-compiling code:
256</p>
257
258<blockquote><pre>
259<span class=keyword>struct</span> <span class=identifier>employee</span>
260<span class=special>{</span>
261  <span class=special>...</span>
262  <span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span> <span class=identifier>salary</span><span class=special>()</span><span class=keyword>const</span><span class=special><b>&amp;</b>;</span> <span class=comment>// note the &amp;</span>
263<span class=special>};</span>
264
265<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
266  <span class=identifier>employee</span><span class=special>,</span>
267  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
268    <span class=special>...</span>
269    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
270      <span class=comment>// compiler error: can't convert &amp;employee::salary to
271      // std::size_t (employee::*)() const</span>
272      <span class=identifier><b>const_mem_fun</b></span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>salary</span><span class=special>&gt;</span>
273    <span class=special>&gt;</span>
274  <span class=special>&gt;</span>
275<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
276</pre></blockquote>
277
278<p>
279The problem here is that the type of <code>&amp;employee::salary</code>, which is
280<a href="https://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions">ref-qualified</a>,
281does not match exactly what <code>const_mem_fun</code> expects. Fortunately, Boost.MultiIndex
282provides a variant to fit:
283</p>
284
285<blockquote><pre>
286<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
287  <span class=identifier>employee</span><span class=special>,</span>
288  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
289    <span class=special>...</span>
290    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
291      <span class=identifier><b>cref_mem_fun</b></span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>salary</span><span class=special>&gt;</span>
292    <span class=special>&gt;</span>
293  <span class=special>&gt;</span>
294<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
295</pre></blockquote>
296
297<p>
298This is the list of all available variants of <code>const_mem_fun</code> and
299<code>mem_fun</code>:
300</p>
301
302<p align="center">
303<table cellspacing="0">
304  <caption><b>Variants of <code>const_mem_fun</code> and <code>mem_fun</code>.</b></caption>
305<tr>
306  <th>&nbsp;Member function example&nbsp;</th>
307  <th>Suitable extractor</th>
308  <th>Behaves as</th>
309</tr>
310<tr>
311  <td><code>int f()const volatile</code></td>
312  <td><a href="../reference/key_extraction.html#cv_mem_fun"><code>cv_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
313  <td align="center" rowspan="3">&nbsp;<code>const_mem_fun</code>&nbsp;</td>
314</tr>
315<tr>
316  <td><code>int f()const&amp;</code></td>
317  <td><a href="../reference/key_extraction.html#cv_mem_fun"><code>cref_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
318</tr>
319<tr>
320  <td><code>int f()const volatile&amp;</code></td>
321  <td><a href="../reference/key_extraction.html#cv_mem_fun"><code>cvref_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
322</tr>
323<tr>
324  <td><code>int f()volatile</code></td>
325  <td><a href="../reference/key_extraction.html#volatile_mem_fun"><code>volatile_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
326  <td align="center" rowspan="3"><code>mem_fun</code></td>
327</tr>
328<tr>
329  <td><code>int f()&amp;</code></td>
330  <td><a href="../reference/key_extraction.html#volatile_mem_fun"><code>ref_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
331</tr>
332<tr>
333  <td><code>int f()volatile&amp;</code></td>
334  <td><a href="../reference/key_extraction.html#volatile_mem_fun"><code>vref_mem_fun</code></a><code>&lt;int,X,&amp;X::f&gt;</code></td>
335</tr>
336</table>
337</p>
338
339<h3><a name="global_fun"><code>global_fun</code></a></h3>
340
341<p>
342Whereas <code>const_mem_fun</code> and its variants are based on a
343given member function of the base type from where the key is extracted,
344<a href="../reference/key_extraction.html#global_fun"><code>global_fun</code></a>
345takes a global function (or static member function) accepting the base
346type as its parameter and returning the key:
347</p>
348
349<blockquote><pre>
350<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
351<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
352<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>global_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
353
354<span class=keyword>struct</span> <span class=identifier>rectangle</span>
355<span class=special>{</span>
356  <span class=keyword>int</span> <span class=identifier>x0</span><span class=special>,</span><span class=identifier>y0</span><span class=special>;</span>
357  <span class=keyword>int</span> <span class=identifier>x1</span><span class=special>,</span><span class=identifier>y1</span><span class=special>;</span>
358<span class=special>};</span>
359
360<span class=keyword>unsigned</span> <span class=keyword>long</span> <span class=identifier>area</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>rectangle</span><span class=special>&amp;</span> <span class=identifier>r</span><span class=special>)</span>
361<span class=special>{</span>
362  <span class=keyword>return</span> <span class=special>(</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>)(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x0</span><span class=special>)*(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>x0</span><span class=special>)+</span>
363         <span class=special>(</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>)(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y0</span><span class=special>)*(</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y1</span><span class=special>-</span><span class=identifier>r</span><span class=special>.</span><span class=identifier>y0</span><span class=special>);</span>
364<span class=special>}</span>
365
366<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
367  <span class=identifier>rectangle</span><span class=special>,</span>
368  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
369    <span class=comment>// sort by increasing area</span>
370    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>global_fun</span><span class=special>&lt;</span><span class=keyword>const</span> <span class=identifier>rectangle</span><span class=special>&amp;,</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>,&amp;</span><span class=identifier>area</span><span class=special>&gt;</span> <span class=special>&gt;</span>
371  <span class=special>&gt;</span>
372<span class=special>&gt;</span> <span class=identifier>rectangle_container</span><span class=special>;</span>
373</pre></blockquote>
374
375<p>
376The specification of <code>global_fun</code> obeys the following syntax:
377</p>
378
379<blockquote><pre>
380<span class=identifier>global_fun</span><span class=special>&lt;</span><span class=identifier><i>(argument type)</i></span><span class=special>,</span><span class=identifier><i>(key type)</i></span><span class=special>,</span><span class=identifier><i>(pointer to function)</i></span><span class=special>&gt;</span>
381</pre></blockquote>
382
383<p>
384where the argument type and key type must match <i>exactly</i> those in the
385signature of the function used; for instance, in the example above the argument
386type is <code>const rectangle&amp;</code>, without omitting the "<code>const</code>"
387and "<code>&amp;</code>" parts. So, although most of the time the base type will be
388accepted by constant reference, <code>global_fun</code> is also prepared to take
389functions accepting their argument by value or by non-constant reference: this
390latter case cannot generally be used directly in the specification of
391<code>multi_index_container</code>s as their elements are treated as constant,
392but the section on <a href="#advanced_key_extractors">advanced features
393of Boost.MultiIndex key extractors</a> describes valid use cases of
394key extraction based on such functions with a non-constant reference argument.
395</p>
396
397<p><a href="../examples.html#example2">Example 2</a> in the examples section
398uses <code>gobal_fun</code>.
399<p>
400
401<h2><a name="user_defined_key_extractors">User-defined key extractors</a></h2>
402
403<p>
404Although the <a href="#predefined_key_extractors">predefined key extractors</a>
405provided by Boost.MultiIndex are intended to serve most cases,
406the user can also provide her own key extractors in more exotic situations,
407as long as these conform to the
408<a href="../reference/key_extraction.html#key_extractors"><code>Key
409Extractor</code></a> concept.
410</p>
411
412<blockquote><pre>
413<span class=comment>// some record class</span>
414<span class=keyword>struct</span> <span class=identifier>record</span>
415<span class=special>{</span>
416  <span class=identifier>boost</span><span class=special>::</span><span class=identifier>gregorian</span><span class=special>::</span><span class=identifier>date</span> <span class=identifier>d</span><span class=special>;</span>
417  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span>            <span class=identifier>str</span><span class=special>;</span>
418<span class=special>};</span>
419
420<span class=comment>// extracts a record's year</span>
421<span class=keyword>struct</span> <span class=identifier>record_year</span>
422<span class=special>{</span>
423  <span class=comment>// result_type typedef required by Key Extractor concept</span>
424  <span class=keyword>typedef</span> <span class=identifier>boost</span><span class=special>::</span><span class=identifier>gregorian</span><span class=special>::</span><span class=identifier>greg_year</span> <span class=identifier>result_type</span><span class=special>;</span>
425
426  <span class=identifier>result_type</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>record</span><span class=special>&amp;</span> <span class=identifier>r</span><span class=special>)</span><span class=keyword>const</span> <span class=comment>// operator() must be const</span>
427  <span class=special>{</span>
428    <span class=keyword>return</span> <span class=identifier>r</span><span class=special>.</span><span class=identifier>d</span><span class=special>.</span><span class=identifier>year</span><span class=special>();</span>
429  <span class=special>}</span>
430<span class=special>};</span>
431
432<span class=comment>// example of use of the previous key extractor</span>
433<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
434  <span class=identifier>record</span><span class=special>,</span>
435  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
436    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>record_year</span><span class=special>&gt;</span> <span class=comment>// sorted by record's year</span>
437  <span class=special>&gt;</span>
438<span class=special>&gt;</span> <span class=identifier>record_log</span><span class=special>;</span>
439</pre></blockquote>
440
441<p>
442<a href="../examples.html#example6">Example 6</a> in the examples section
443applies some user-defined key extractors in a complex scenario where
444keys are accessed via pointers.
445</p>
446
447<h2><a name="composite_keys">Composite keys</a></h2>
448
449<p>
450In relational databases, composite keys depend on two or more fields of a given table.
451The analogous concept in Boost.MultiIndex is modeled by means of
452<a href="../reference/key_extraction.html#composite_key">
453<code>composite_key</code></a>, as shown in the example:
454</p>
455
456<blockquote><pre>
457<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index_container</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
458<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
459<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
460<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>composite_key</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
461
462<span class=keyword>struct</span> <span class=identifier>phonebook_entry</span>
463<span class=special>{</span>
464  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>;</span>
465  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>;</span>
466  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>;</span>
467
468  <span class=identifier>phonebook_entry</span><span class=special>(</span>
469    <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>family_name</span><span class=special>,</span>
470    <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>given_name</span><span class=special>,</span>
471    <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>phone_number</span><span class=special>):</span>
472    <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>
473  <span class=special>{}</span>
474<span class=special>};</span>
475
476<span class=comment>// define a multi_index_container with a composite key on
477// (family_name,given_name)</span>
478<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
479  <span class=identifier>phonebook_entry</span><span class=special>,</span>
480  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
481    <span class=comment>// non-unique as some subscribers might have more than one number</span>
482    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
483      <span class=identifier>composite_key</span><span class=special>&lt;</span>
484        <span class=identifier>phonebook_entry</span><span class=special>,</span>
485        <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>&gt;,</span>
486        <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>&gt;</span>
487      <span class=special>&gt;</span>
488    <span class=special>&gt;,</span>
489    <span class=identifier>ordered_unique</span><span class=special>&lt;</span> <span class=comment>// unique as numbers belong to only one subscriber</span>
490      <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>&gt;</span>
491    <span class=special>&gt;</span>
492  <span class=special>&gt;</span>
493<span class=special>&gt;</span> <span class=identifier>phonebook</span><span class=special>;</span>
494</pre></blockquote>
495
496<p>
497<code>composite_key</code> accepts two or more key extractors on the same
498value (here, <code>phonebook_entry</code>). Lookup operations on a composite
499key are accomplished by passing tuples with the values searched:
500</p>
501
502<blockquote><pre>
503<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
504<span class=special>...</span>
505<span class=comment>// search for Dorothea White's number</span>
506<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>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=string>&quot;White&quot;</span><span class=special>,</span><span class=string>&quot;Dorothea&quot;</span><span class=special>));</span>
507<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>-&gt;</span><span class=identifier>phone_number</span><span class=special>;</span>
508</pre></blockquote>
509
510<p>
511Composite keys are sorted by lexicographical order, i.e. sorting is performed
512by the first key, then the second key if the first one is equal, etc. This
513order allows for partial searches where only the first keys are specified:
514</p>
515
516<blockquote><pre>
517<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
518<span class=special>...</span>
519<span class=comment>// look for all Whites</span>
520<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</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>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
521  <span class=identifier>pb</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=string>&quot;White&quot;</span><span class=special>));</span>
522</pre></blockquote>
523
524<p>
525As a notational convenience, when only the first key is specified it is possible
526to pass the argument directly without including it into a tuple:
527</p>
528
529<blockquote><pre>
530<span class=identifier>phonebook</span> <span class=identifier>pb</span><span class=special>;</span>
531<span class=special>...</span>
532<span class=comment>// look for all Whites</span>
533<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</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>&gt;</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=string>&quot;White&quot;</span><span class=special>);</span>
534</pre></blockquote>
535
536<p>
537On the other hand, partial searches without specifying the first keys are not
538allowed.
539</p>
540
541<p>
542By default, the corresponding <code>std::less</code> predicate is used
543for each subkey of a composite key. Alternate comparison predicates can
544be specified with <a href="../reference/key_extraction.html#composite_key_compare">
545<code>composite_key_compare</code></a>:
546</p>
547
548<blockquote><pre>
549<span class=comment>// phonebook with given names in reverse order</span>
550
551<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
552  <span class=identifier>phonebook_entry</span><span class=special>,</span>
553  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
554    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
555      <span class=identifier>composite_key</span><span class=special>&lt;</span>
556        <span class=identifier>phonebook_entry</span><span class=special>,</span>
557        <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>&gt;,</span>
558        <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>&gt;</span>
559      <span class=special>&gt;,</span>
560      <span class=identifier>composite_key_compare</span><span class=special>&lt;</span>
561        <span class=identifier>std</span><span class=special>::</span><span class=identifier>less</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;,</span>   <span class=comment>// family names sorted as by default</span>
562        <span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt;</span> <span class=comment>// given names reversed</span>
563      <span class=special>&gt;</span>
564    <span class=special>&gt;,</span>
565    <span class=identifier>ordered_unique</span><span class=special>&lt;</span>
566      <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>&gt;</span>
567    <span class=special>&gt;</span>
568  <span class=special>&gt;</span>
569<span class=special>&gt;</span> <span class=identifier>phonebook</span><span class=special>;</span>
570</pre></blockquote>
571
572<p>
573See <a href="../examples.html#example7">example 7</a> in the examples section
574for an application of <code>composite_key</code>.
575</p>
576
577<h3><a name="composite_keys_hash">Composite keys and hashed indices</a></h3>
578
579<p>
580Composite keys can also be used with hashed indices in a straightforward manner:
581</p>
582
583<blockquote><pre>
584<span class=keyword>struct</span> <span class=identifier>street_entry</span>
585<span class=special>{</span>
586  <span class=comment>// quadrant coordinates</span>
587  <span class=keyword>int</span> <span class=identifier>x</span><span class=special>;</span>
588  <span class=keyword>int</span> <span class=identifier>y</span><span class=special>;</span>
589
590  <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>name</span><span class=special>;</span>
591
592  <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>&amp;</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>
593<span class=special>};</span>
594
595<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
596  <span class=identifier>street_entry</span><span class=special>,</span>
597  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
598    <span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by quadrant coordinates</span>
599      <span class=identifier>composite_key</span><span class=special>&lt;</span>
600        <span class=identifier>street_entry</span><span class=special>,</span>
601        <span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>&gt;,</span>
602        <span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>&gt;</span>
603      <span class=special>&gt;</span>
604    <span class=special>&gt;,</span>
605    <span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by street name</span>
606      <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span>
607    <span class=special>&gt;</span>
608  <span class=special>&gt;</span>
609<span class=special>&gt;</span> <span class=identifier>street_locator</span><span class=special>;</span>
610
611<span class=identifier>street_locator</span> <span class=identifier>sl</span><span class=special>;</span>
612<span class=special>...</span>
613<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>
614<span class=special>{</span>
615  <span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</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>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
616    <span class=identifier>sl</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</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>
617
618  <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>
619    <span class=identifier>std</span><span class=special>::</span><span class=identifier>cout</span><span class=special>&lt;&lt;</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>-&gt;</span><span class=identifier>name</span><span class=special>&lt;&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;</span>
620    <span class=special>++</span><span class=identifier>p</span><span class=special>.</span><span class=identifier>first</span><span class=special>;</span>
621  <span class=special>}</span>
622<span class=special>}</span>
623</pre></blockquote>
624
625<p>
626Note that hashing is automatically taken care of: <code>boost::hash</code> is
627specialized to hash a composite key as a function of the <code>boost::hash</code>
628values of its elements. Should we need to specify different hash functions for the
629elements of a composite key, we can explicitly do so by using the
630<a href="../reference/key_extraction.html#composite_key_hash"><code>composite_key_hash</code></a>
631utility:
632</p>
633
634<blockquote><pre>
635<span class=keyword>struct</span> <span class=identifier>tuned_int_hash</span>
636<span class=special>{</span>
637  <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>
638  <span class=special>{</span>
639    <span class=comment>// specially tuned hash for this application</span>
640  <span class=special>}</span>
641<span class=special>};</span>
642
643<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
644  <span class=identifier>street_entry</span><span class=special>,</span>
645  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
646    <span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by quadrant coordinates</span>
647      <span class=identifier>composite_key</span><span class=special>&lt;</span>
648        <span class=identifier>street_entry</span><span class=special>,</span>
649        <span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>x</span><span class=special>&gt;,</span>
650        <span class=identifier>member</span><span class=special>&lt;</span><span class=identifier>street_entry</span><span class=special>,</span><span class=keyword>int</span><span class=special>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>y</span><span class=special>&gt;</span>
651      <span class=special>&gt;,</span>
652      <span class=identifier>composite_key_hash</span><span class=special>&lt;</span>
653        <span class=identifier>tuned_int_hash</span><span class=special>,</span>
654        <span class=identifier>tuned_int_hash</span>
655      <span class=special>&gt;</span>
656    <span class=special>&gt;,</span>
657    <span class=identifier>hashed_non_unique</span><span class=special>&lt;</span> <span class=comment>// indexed by street name</span>
658      <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>street_entry</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span>
659    <span class=special>&gt;</span>
660  <span class=special>&gt;</span>
661<span class=special>&gt;</span> <span class=identifier>street_locator</span><span class=special>;</span>
662</pre></blockquote>
663
664<p>
665Also, equality of composite keys can be tuned with
666<a href="../reference/key_extraction.html#composite_key_equal_to"><code>composite_key_equal_to</code></a>,
667though in most cases the default equality predicate (relying on
668the <code>std::equal_to</code> instantiations for the element types)
669will be the right choice.
670</p>
671
672<p>
673Unlike with ordered indices, we cannot perform partial searches specifying
674only the first elements of a composite key:
675</p>
676
677<blockquote><pre>
678<span class=comment>// try to locate streets in quadrants with x==0
679// compile-time error: hashed indices do not allow such operations</span>
680<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special>&lt;</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>&gt;</span> <span class=identifier>p</span><span class=special>=</span>
681  <span class=identifier>sl</span><span class=special>.</span><span class=identifier>equal_range</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>make_tuple</span><span class=special>(</span><span class=number>0</span><span class=special>));</span>
682</pre></blockquote>
683
684<p>
685The reason for this limitation is quite logical: as the hash value of a composite
686key depends on all of its elements, it is impossible to calculate it from
687partial information.
688</p>
689
690<h2><a name="key">C++17 terse key specification syntax</a></h2>
691
692<p>
693C++17 introduces the declaration of <code>auto</code> template parameters, which can be
694taken advantage of to eliminate some redundancy in the specification of Boost.MultiIndex
695predefined key extractors. For instance, instead of the classical:
696</p>
697
698<blockquote><pre>
699<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
700  <span class=identifier>employee</span><span class=special>,</span>
701  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
702    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
703    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;,</span>
704    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span>
705      <span class=identifier>const_mem_fun</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>size_t</span><span class=special>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name_length</span><span class=special>&gt;</span>
706    <span class=special>&gt;</span>
707  <span class=special>&gt;</span>
708<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
709</pre></blockquote>
710
711one can now write:
712
713<blockquote><pre>
714<span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>multi_index</span><span class=special>/</span><span class=identifier>key</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
715<span class=special>...</span>
716<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
717  <span class=identifier>employee</span><span class=special>,</span>
718  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
719    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=identifier>employee</span><span class=special>&gt;&gt;,</span>
720    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier><b>key</b></span><span class=special><b>&lt;&amp;</b></span><span class=identifier><b>employee</b></span><span class=special><b>::</b></span><span class=identifier><b>name</b></span><span class=special><b>&gt;</b>&gt;,</span>
721    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier><b>key</b></span><span class=special><b>&lt;&amp;</b></span><span class=identifier><b>employee</b></span><span class=special><b>::</b></span><span class=identifier><b>name_length</b></span><span class=special><b>&gt;</b>&gt;</span>
722  <span class=special>&gt;</span>
723<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
724</pre></blockquote>
725
726<p>
727which results in the exact same defined type, as
728<a href="../reference/key_extraction.html#key"><code>key</code></a> constructs are mere
729aliases for the old syntax. <code>key</code> can be used to shorten the specification of
730<a href="../reference/key_extraction.html#member"><code>member</code></a>,
731<a href="../reference/key_extraction.html#const_mem_fun"><code>const_mem_fun</code></a>
732(and <a href="../reference/key_extraction.html#cv_mem_fun">variants</a>),
733<a href="../reference/key_extraction.html#mem_fun"><code>mem_fun</code></a>
734(and <a href="../reference/key_extraction.html#volatile_mem_fun">variants</a>),
735<a href="../reference/key_extraction.html#global_fun"><code>global_fun</code></a>
736and, with additional terseness benefits,
737<a href="../reference/key_extraction.html#composite_key"><code>composite_key</code></a>:
738</p>
739
740<blockquote><pre>
741<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
742  <span class=identifier>phonebook_entry</span><span class=special>,</span>
743  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
744    <span class=comment>// composite key on family name and given name</span>
745    <span class=identifier>ordered_non_unique</span><span class=special>&lt;
746      </span><span class=identifier><b>key</b></span><span class=special><b>&lt;&amp;</b></span><span class=identifier><b>phonebook_entry</b></span><span class=special><b>::</b></span><span class=identifier><b>family_name</b></span><span class=special><b>,&amp;</b></span><span class=identifier><b>phonebook_entry</b></span><span class=special><b>::</b></span><span class=identifier><b>given_name</b></span><span class=special><b>&gt;</b></span>
747    <span class=special>&gt;,</span>
748    <span class=comment>// unique index on phone number</span>
749    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>key</span><span class=special>&lt;&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>phone_number</span><span class=special>&gt;&gt;</span>
750  <span class=special>&gt;</span>
751<span class=special>&gt;</span> <span class=identifier>phonebook</span><span class=special>;</span>
752</pre></blockquote>
753
754In this example, the first usage of <code>key</code> substitutes for the
755decidedly more cumbersome:
756
757<blockquote><pre>
758<span class=identifier>composite_key</span><span class=special>&lt;</span>
759  <span class=identifier>phonebook_entry</span><span class=special>,</span>
760  <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>family_name</span><span class=special>&gt;,</span>
761  <span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>phonebook_entry</span><span class=special>::</span><span class=identifier>given_name</span><span class=special>&gt;</span>
762<span class=special>&gt;</span>
763</pre></blockquote>
764
765Note that we did not even have to specify the first <code>phonebook_entry</code>
766argument: the internal machinery of <code>key</code> automatically deduces it for
767us. Check the <a href="../reference/key_extraction.html#key_synopsis">reference</a>
768for technical details.
769
770<h2><a name="advanced_key_extractors">Advanced features of Boost.MultiIndex key
771extractors</a></h2>
772
773<p>
774The <a href="../reference/key_extraction.html#key_extractors"><code>Key Extractor</code></a>
775concept allows the same object to extract keys from several different types,
776possibly through suitably defined overloads of <code>operator()</code>:
777</p>
778
779<blockquote><pre>
780<span class=comment>// example of a name extractor from employee and employee *</span>
781<span class=keyword>struct</span> <span class=identifier>name_extractor</span>
782<span class=special>{</span>
783  <span class=keyword>typedef</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>result_type</span><span class=special>;</span>
784
785  <span class=keyword>const</span> <span class=identifier>result_type</span><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&amp;</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>
786  <span class=identifier>result_type</span><span class=special>&amp;</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>-&gt;</span><span class=identifier>name</span><span class=special>;}</span>
787<span class=special>};</span>
788
789<span class=comment>// name_extractor can handle elements of type employee...</span>
790<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
791  <span class=identifier>employee</span><span class=special>,</span>
792  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
793    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>name_extractor</span><span class=special>&gt;</span>
794  <span class=special>&gt;</span>
795<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
796
797<span class=comment>// ...as well as elements of type employee *</span>
798<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
799  <span class=identifier>employee</span><span class=special>*,</span>
800  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
801    <span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>name_extractor</span><span class=special>&gt;</span>
802  <span class=special>&gt;</span>
803<span class=special>&gt;</span> <span class=identifier>employee_ptr_set</span><span class=special>;</span>
804</pre></blockquote>
805
806<p>
807This possibility is fully exploited by predefined key extractors provided
808by Boost.MultiIndex, making it simpler to define <code>multi_index_container</code>s
809where elements are pointers or references to the actual objects. The following
810specifies a <code>multi_index_container</code> of pointers to employees sorted by their
811names.
812</p>
813
814<blockquote><pre>
815<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
816  <span class=identifier>employee</span> <span class=special>*,</span>
817  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
818    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
819<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
820</pre></blockquote>
821
822<p>
823Note that this is specified in exactly the same manner as a <code>multi_index_container</code>
824of actual <code>employee</code> objects: <code>member</code> takes care of the
825extra dereferencing needed to gain access to <code>employee::name</code>. A similar
826functionality is provided for interoperability with reference wrappers from
827<a href="../../../../doc/html/ref.html">Boost.Ref</a>:
828</p>
829
830<blockquote><pre>
831<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special>&lt;</span>
832  <span class=identifier>boost</span><span class=special>::</span><span class=identifier>reference_wrapper</span><span class=special>&lt;</span><span class=keyword>const</span> <span class=identifier>employee</span><span class=special>&gt;,</span>
833  <span class=identifier>indexed_by</span><span class=special>&lt;</span>
834    <span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>member</span><span class=special>&lt;</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>,&amp;</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=special>&gt;</span>
835<span class=special>&gt;</span> <span class=identifier>employee_set</span><span class=special>;</span>
836</pre></blockquote>
837
838<p>
839In fact, support for pointers is further extended to accept what we call
840<i>chained pointers</i>. Such a chained pointer is defined by induction as a raw or
841smart pointer or iterator to the actual element, to a reference wrapper of the
842element or <i>to another chained pointer</i>; that is, chained pointers are arbitrary
843compositions of pointer-like types ultimately dereferencing
844to the element from where the key is to be extracted. Examples of chained
845pointers to <code>employee</code> are:
846<ul>
847  <li><code>employee *</code>,</li>
848  <li><code>const employee *</code>,</li>
849  <li><code>std::unique_ptr&lt;employee></code>,</li>
850  <li><code>std::list&lt;boost::reference_wrapper&lt;employee> >::iterator</code>,</li>
851  <li><code>employee **</code>,</li>
852  <li><code>boost::shared_ptr&lt;const employee *></code>.</li>
853</ul>
854In general, chained pointers with dereferencing distance greater than 1 are not
855likely to be used in a normal program, but they can arise in frameworks
856which construct "views" as <code>multi_index_container</code>s from preexisting
857<code>multi_index_container</code>s.
858</p>
859
860<p>
861In order to present a short summary of the different usages of Boost.MultiIndex
862key extractors in the presence of reference wrappers and pointers, consider the
863following final type:
864</p>
865
866<blockquote><pre>
867<span class=keyword>struct</span> <span class=identifier>T</span>
868<span class=special>{</span>
869  <span class=keyword>int</span>        <span class=identifier>i</span><span class=special>;</span>
870  <span class=keyword>const</span> <span class=keyword>int</span>  <span class=identifier>j</span><span class=special>;</span>
871  <span class=keyword>int</span>        <span class=identifier>f</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
872  <span class=keyword>int</span>        <span class=identifier>g</span><span class=special>();</span>
873  <span class=keyword>static</span> <span class=keyword>int</span> <span class=identifier>gf</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>T</span><span class=special>&amp;);</span>
874  <span class=keyword>static</span> <span class=keyword>int</span> <span class=identifier>gg</span><span class=special>(</span><span class=identifier>T</span><span class=special>&amp;);</span>
875<span class=special>};</span>
876</pre></blockquote>
877
878<p>
879The table below lists the appropriate key extractors to be used for
880different pointer and reference wrapper types based on <code>T</code>, for
881each of its members.
882</p>
883
884<p align="center">
885<table cellspacing="0">
886  <caption><b>Use cases for Boost.MultiIndex key extractors.</b></caption>
887<tr>
888  <th>element type</th>
889  <th>&nbsp;key&nbsp;</th>
890  <th>key extractor</th>
891  <th>applicable to<br><code>const</code> elements?</th>
892  <th>read/write?</th>
893</tr>
894<tr>
895  <td align="center" rowspan="6"><code>T</code></td>
896  <td><code>i</code></td>
897  <td><code>member&lt;T,int,&amp;T::i></code></td>
898  <td align="center">yes</td>
899  <td align="center">yes</td>
900</tr>
901<tr>
902  <td><code>j</code></td>
903  <td><code>member&lt;T,const int,&amp;T::j></code></td>
904  <td align="center">yes</td>
905  <td align="center">no</td>
906</tr>
907<tr>
908  <td><code>f()</code></td>
909  <td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
910  <td align="center">yes</td>
911  <td align="center">no</td>
912</tr>
913<tr>
914  <td><code>g()</code></td>
915  <td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
916  <td align="center">no</td>
917  <td align="center">no</td>
918</tr>
919<tr>
920  <td><code>gf()</code></td>
921  <td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
922  <td align="center">yes</td>
923  <td align="center">no</td>
924</tr>
925<tr>
926  <td><code>gg()</code></td>
927  <td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
928  <td align="center">no</td>
929  <td align="center">no</td>
930</tr>
931
932<tr class="odd_tr">
933  <td align="center" rowspan="6"><code>reference_wrapper&lt;T></code></td>
934  <td><code>i</code></td>
935  <td><code>member&lt;T,int,&amp;T::i></code></td>
936  <td align="center">yes</td>
937  <td align="center">yes</td>
938</tr>
939<tr class="odd_tr">
940  <td><code>j</code></td>
941  <td><code>member&lt;T,const int,&amp;T::j></code></td>
942  <td align="center">yes</td>
943  <td align="center">no</td>
944</tr>
945<tr class="odd_tr">
946  <td><code>f()</code></td>
947  <td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
948  <td align="center">yes</td>
949  <td align="center">no</td>
950</tr>
951<tr class="odd_tr">
952  <td><code>g()</code></td>
953  <td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
954  <td align="center">yes</td>
955  <td align="center">no</td>
956</tr>
957<tr class="odd_tr">
958  <td><code>gf()</code></td>
959  <td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
960  <td align="center">yes</td>
961  <td align="center">no</td>
962</tr>
963<tr class="odd_tr">
964  <td><code>gg()</code></td>
965  <td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
966  <td align="center">yes</td>
967  <td align="center">no</td>
968</tr>
969
970<tr>
971  <td align="center" rowspan="6"><code>reference_wrapper&lt;const T></code></td>
972  <td><code>i</code></td>
973  <td><code>member&lt;T,const int,&amp;T::i></code></td>
974  <td align="center">yes</td>
975  <td align="center">no</td>
976</tr>
977<tr>
978  <td><code>j</code></td>
979  <td><code>member&lt;T,const int,&amp;T::j></code></td>
980  <td align="center">yes</td>
981  <td align="center">no</td>
982</tr>
983<tr>
984  <td><code>f()</code></td>
985  <td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
986  <td align="center">yes</td>
987  <td align="center">no</td>
988</tr>
989<tr>
990  <td><code>g()</code></td>
991  <td colspan="3">&nbsp;</td>
992</tr>
993<tr>
994  <td><code>gf()</code></td>
995  <td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
996  <td align="center">yes</td>
997  <td align="center">no</td>
998</tr>
999<tr>
1000  <td><code>gg()</code></td>
1001  <td colspan="3">&nbsp;</td>
1002</tr>
1003
1004<tr class="odd_tr">
1005  <td align="center" rowspan="6">chained pointer to <code>T</code><br>
1006    or to <code>reference_wrapper&lt;T></code></td>
1007  <td><code>i</code></td>
1008  <td><code>member&lt;T,int,&amp;T::i></code></td>
1009  <td align="center">yes</td>
1010  <td align="center">yes</td>
1011</tr>
1012<tr class="odd_tr">
1013  <td><code>j</code></td>
1014  <td><code>member&lt;T,const int,&amp;T::j></code></td>
1015  <td align="center">yes</td>
1016  <td align="center">no</td>
1017</tr>
1018<tr class="odd_tr">
1019  <td><code>f()</code></td>
1020  <td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
1021  <td align="center">yes</td>
1022  <td align="center">no</td>
1023</tr>
1024<tr class="odd_tr">
1025  <td><code>g()</code></td>
1026  <td><code>mem_fun&lt;T,int,&amp;T::g></code></td>
1027  <td align="center">yes</td>
1028  <td align="center">no</td>
1029</tr>
1030<tr class="odd_tr">
1031  <td><code>gf()</code></td>
1032  <td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
1033  <td align="center">yes</td>
1034  <td align="center">no</td>
1035</tr>
1036<tr class="odd_tr">
1037  <td><code>gg()</code></td>
1038  <td><code>global_fun&lt;T&amp;,int,&amp;T::gg></code></td>
1039  <td align="center">yes</td>
1040  <td align="center">no</td>
1041</tr>
1042
1043<tr>
1044  <td align="center" rowspan="6">chained pointer to <code>const T</code><br>
1045    or to <code>reference_wrapper&lt;const T></code></td>
1046  <td><code>i</code></td>
1047  <td><code>member&lt;T,const int,&amp;T::i></code></td>
1048  <td align="center">yes</td>
1049  <td align="center">no</td>
1050</tr>
1051<tr>
1052  <td><code>j</code></td>
1053  <td><code>member&lt;T,const int,&amp;T::j></code></td>
1054  <td align="center">yes</td>
1055  <td align="center">no</td>
1056</tr>
1057<tr>
1058  <td><code>f()</code></td>
1059  <td><code>const_mem_fun&lt;T,int,&amp;T::f></code></td>
1060  <td align="center">yes</td>
1061  <td align="center">no</td>
1062</tr>
1063<tr>
1064  <td><code>g()</code></td>
1065  <td colspan="3">&nbsp;</td>
1066</tr>
1067<tr>
1068  <td><code>gf()</code></td>
1069  <td><code>global_fun&lt;const T&amp;,int,&amp;T::gf></code></td>
1070  <td align="center">yes</td>
1071  <td align="center">no</td>
1072</tr>
1073<tr>
1074  <td><code>gg()</code></td>
1075  <td colspan="3">&nbsp;</td>
1076</tr>
1077
1078</table>
1079</p>
1080
1081<p>
1082The column "applicable to <code>const</code> elements?" states whether the
1083corresponding key extractor can be used when passed constant elements (this
1084relates to the elements specified in the first column, not the referenced
1085<code>T</code> objects). The only negative cases are for <code>T::g</code> and
1086<code>T:gg</code> when the elements are raw <code>T</code> objects, which make sense
1087as we are dealing with a non-constant member function (<code>T::g</code>)
1088and a function taking <code>T</code> by
1089non-constant reference: this also implies that <code>multi_index_container</code>s
1090of elements of <code>T</code> cannot be sorted by <code>T::g</code> or <code>T::gg</code>, because
1091elements contained within a <code>multi_index_container</code> are treated as constant.
1092</p>
1093
1094<p>
1095The column "read/write?" shows which combinations yield
1096<a href="#read_write_key_extractors">read/write key extractors</a>.
1097</p>
1098
1099<p>
1100Some care has to be taken to preserve <code>const</code>-correctness in the
1101specification of <code>member</code> key extractors: in some sense, the <code>const</code>
1102qualifier is carried along to the member part, even if that particular
1103member is not defined as <code>const</code>. For instance, if the elements
1104are of type <code>const T *</code>, sorting by <code>T::i</code> is <i>not</i>
1105specified as <code>member&lt;const T,int,&amp;T::i></code>, but rather as
1106<code>member&lt;T,const int,&amp;T::i></code>.
1107</p>
1108
1109<p>
1110For practical demonstrations of use of these key extractors, refer to
1111<a href="../examples.html#example2">example 2</a> and
1112<a href="../examples.html#example6">example 6</a> in the examples section.
1113</p>
1114
1115<hr>
1116
1117<div class="prev_link"><a href="indices.html"><img src="../prev.gif" alt="index types" border="0"><br>
1118Index types
1119</a></div>
1120<div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.MultiIndex tutorial" border="0"><br>
1121Boost.MultiIndex tutorial
1122</a></div>
1123<div class="next_link"><a href="creation.html"><img src="../next.gif" alt="container creation" border="0"><br>
1124Container creation
1125</a></div><br clear="all" style="clear: all;">
1126
1127<br>
1128
1129<p>Revised April 19th 2020</p>
1130
1131<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
1132Distributed under the Boost Software
1133License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
1134LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
1135http://www.boost.org/LICENSE_1_0.txt</a>)
1136</p>
1137
1138</body>
1139</html>
1140