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<const Key,T></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><</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>></span> 119<span class=preprocessor>#include</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>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 120<span class=preprocessor>#include</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>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 121 122<span class=identifier>multi_index_container</span><span class=special><</span> 123 <span class=keyword>int</span><span class=special>,</span> 124 <span class=identifier>indexed_by</span><span class=special><</span> 125 <span class=identifier>ordered_unique</span><span class=special><</span> 126 <span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=comment>// the key is the entire element</span> 127 <span class=special>></span> 128 <span class=special>></span> 129<span class=special>></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><</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>></span> 143<span class=preprocessor>#include</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>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 144<span class=preprocessor>#include</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>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 145<span class=preprocessor>#include</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>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 146 147<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span> 148 <span class=identifier>employee</span><span class=special>,</span> 149 <span class=identifier>indexed_by</span><span class=special><</span> 150 <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> 151 <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> 152 <span class=identifier>ordered_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> 153 <span class=special>></span> 154<span class=special>></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><</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>></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><</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>></span> 191<span class=preprocessor>#include</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>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 192<span class=preprocessor>#include</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>identity</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 193<span class=preprocessor>#include</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>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 194<span class=preprocessor>#include</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>mem_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></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>&</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><(</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> 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><</span> 210 <span class=identifier>employee</span><span class=special>,</span> 211 <span class=identifier>indexed_by</span><span class=special><</span> 212 <span class=comment>// sort by employee::operator<</span> 213 <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> 214 215 <span class=comment>// sort by less<string> on name</span> 216 <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> 217 218 <span class=comment>// sort by less<int> on name_length()</span> 219 <span class=identifier>ordered_non_unique</span><span class=special><</span> 220 <span class=identifier>const_mem_fun</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>size_t</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name_length</span><span class=special>></span> 221 <span class=special>></span> 222 <span class=special>></span> 223<span class=special>></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><</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>></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>&</b>;</span> <span class=comment>// note the &</span> 263<span class=special>};</span> 264 265<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span> 266 <span class=identifier>employee</span><span class=special>,</span> 267 <span class=identifier>indexed_by</span><span class=special><</span> 268 <span class=special>...</span> 269 <span class=identifier>ordered_non_unique</span><span class=special><</span> 270 <span class=comment>// compiler error: can't convert &employee::salary to 271 // std::size_t (employee::*)() const</span> 272 <span class=identifier><b>const_mem_fun</b></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>size_t</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>salary</span><span class=special>></span> 273 <span class=special>></span> 274 <span class=special>></span> 275<span class=special>></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>&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><</span> 287 <span class=identifier>employee</span><span class=special>,</span> 288 <span class=identifier>indexed_by</span><span class=special><</span> 289 <span class=special>...</span> 290 <span class=identifier>ordered_non_unique</span><span class=special><</span> 291 <span class=identifier><b>cref_mem_fun</b></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>size_t</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>salary</span><span class=special>></span> 292 <span class=special>></span> 293 <span class=special>></span> 294<span class=special>></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> Member function example </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><int,X,&X::f></code></td> 313 <td align="center" rowspan="3"> <code>const_mem_fun</code> </td> 314</tr> 315<tr> 316 <td><code>int f()const&</code></td> 317 <td><a href="../reference/key_extraction.html#cv_mem_fun"><code>cref_mem_fun</code></a><code><int,X,&X::f></code></td> 318</tr> 319<tr> 320 <td><code>int f()const volatile&</code></td> 321 <td><a href="../reference/key_extraction.html#cv_mem_fun"><code>cvref_mem_fun</code></a><code><int,X,&X::f></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><int,X,&X::f></code></td> 326 <td align="center" rowspan="3"><code>mem_fun</code></td> 327</tr> 328<tr> 329 <td><code>int f()&</code></td> 330 <td><a href="../reference/key_extraction.html#volatile_mem_fun"><code>ref_mem_fun</code></a><code><int,X,&X::f></code></td> 331</tr> 332<tr> 333 <td><code>int f()volatile&</code></td> 334 <td><a href="../reference/key_extraction.html#volatile_mem_fun"><code>vref_mem_fun</code></a><code><int,X,&X::f></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><</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>></span> 351<span class=preprocessor>#include</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>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 352<span class=preprocessor>#include</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>global_fun</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></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>&</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><</span> 367 <span class=identifier>rectangle</span><span class=special>,</span> 368 <span class=identifier>indexed_by</span><span class=special><</span> 369 <span class=comment>// sort by increasing area</span> 370 <span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>global_fun</span><span class=special><</span><span class=keyword>const</span> <span class=identifier>rectangle</span><span class=special>&,</span><span class=keyword>unsigned</span> <span class=keyword>long</span><span class=special>,&</span><span class=identifier>area</span><span class=special>></span> <span class=special>></span> 371 <span class=special>></span> 372<span class=special>></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><</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>></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&</code>, without omitting the "<code>const</code>" 387and "<code>&</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>&</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><</span> 434 <span class=identifier>record</span><span class=special>,</span> 435 <span class=identifier>indexed_by</span><span class=special><</span> 436 <span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>record_year</span><span class=special>></span> <span class=comment>// sorted by record's year</span> 437 <span class=special>></span> 438<span class=special>></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><</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>></span> 458<span class=preprocessor>#include</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>ordered_index</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 459<span class=preprocessor>#include</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>member</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span> 460<span class=preprocessor>#include</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>composite_key</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></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><</span> 479 <span class=identifier>phonebook_entry</span><span class=special>,</span> 480 <span class=identifier>indexed_by</span><span class=special><</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><</span> 483 <span class=identifier>composite_key</span><span class=special><</span> 484 <span class=identifier>phonebook_entry</span><span class=special>,</span> 485 <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> 486 <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> 487 <span class=special>></span> 488 <span class=special>>,</span> 489 <span class=identifier>ordered_unique</span><span class=special><</span> <span class=comment>// unique as numbers belong to only one subscriber</span> 490 <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> 491 <span class=special>></span> 492 <span class=special>></span> 493<span class=special>></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>"White"</span><span class=special>,</span><span class=string>"Dorothea"</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>-></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><</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> 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>"White"</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><</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=string>"White"</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><</span> 552 <span class=identifier>phonebook_entry</span><span class=special>,</span> 553 <span class=identifier>indexed_by</span><span class=special><</span> 554 <span class=identifier>ordered_non_unique</span><span class=special><</span> 555 <span class=identifier>composite_key</span><span class=special><</span> 556 <span class=identifier>phonebook_entry</span><span class=special>,</span> 557 <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> 558 <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> 559 <span class=special>>,</span> 560 <span class=identifier>composite_key_compare</span><span class=special><</span> 561 <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> 562 <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> 563 <span class=special>></span> 564 <span class=special>>,</span> 565 <span class=identifier>ordered_unique</span><span class=special><</span> 566 <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> 567 <span class=special>></span> 568 <span class=special>></span> 569<span class=special>></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>&</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><</span> 596 <span class=identifier>street_entry</span><span class=special>,</span> 597 <span class=identifier>indexed_by</span><span class=special><</span> 598 <span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by quadrant coordinates</span> 599 <span class=identifier>composite_key</span><span class=special><</span> 600 <span class=identifier>street_entry</span><span class=special>,</span> 601 <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> 602 <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> 603 <span class=special>></span> 604 <span class=special>>,</span> 605 <span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by street name</span> 606 <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> 607 <span class=special>></span> 608 <span class=special>></span> 609<span class=special>></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><</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> 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><<</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> 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><</span> 644 <span class=identifier>street_entry</span><span class=special>,</span> 645 <span class=identifier>indexed_by</span><span class=special><</span> 646 <span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by quadrant coordinates</span> 647 <span class=identifier>composite_key</span><span class=special><</span> 648 <span class=identifier>street_entry</span><span class=special>,</span> 649 <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> 650 <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> 651 <span class=special>>,</span> 652 <span class=identifier>composite_key_hash</span><span class=special><</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>></span> 656 <span class=special>>,</span> 657 <span class=identifier>hashed_non_unique</span><span class=special><</span> <span class=comment>// indexed by street name</span> 658 <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> 659 <span class=special>></span> 660 <span class=special>></span> 661<span class=special>></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><</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> 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><</span> 700 <span class=identifier>employee</span><span class=special>,</span> 701 <span class=identifier>indexed_by</span><span class=special><</span> 702 <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> 703 <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> 704 <span class=identifier>ordered_non_unique</span><span class=special><</span> 705 <span class=identifier>const_mem_fun</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>size_t</span><span class=special>,&</span><span class=identifier>employee</span><span class=special>::</span><span class=identifier>name_length</span><span class=special>></span> 706 <span class=special>></span> 707 <span class=special>></span> 708<span class=special>></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><</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>></span> 715<span class=special>...</span> 716<span class=keyword>typedef</span> <span class=identifier>multi_index_container</span><span class=special><</span> 717 <span class=identifier>employee</span><span class=special>,</span> 718 <span class=identifier>indexed_by</span><span class=special><</span> 719 <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> 720 <span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier><b>key</b></span><span class=special><b><&</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>></b>>,</span> 721 <span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier><b>key</b></span><span class=special><b><&</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>></b>></span> 722 <span class=special>></span> 723<span class=special>></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><</span> 742 <span class=identifier>phonebook_entry</span><span class=special>,</span> 743 <span class=identifier>indexed_by</span><span class=special><</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>< 746 </span><span class=identifier><b>key</b></span><span class=special><b><&</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>,&</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>></b></span> 747 <span class=special>>,</span> 748 <span class=comment>// unique index on phone number</span> 749 <span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>key</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> 750 <span class=special>></span> 751<span class=special>></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><</span> 759 <span class=identifier>phonebook_entry</span><span class=special>,</span> 760 <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> 761 <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> 762<span class=special>></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>&</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> 786 <span class=identifier>result_type</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> 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><</span> 791 <span class=identifier>employee</span><span class=special>,</span> 792 <span class=identifier>indexed_by</span><span class=special><</span> 793 <span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>name_extractor</span><span class=special>></span> 794 <span class=special>></span> 795<span class=special>></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><</span> 799 <span class=identifier>employee</span><span class=special>*,</span> 800 <span class=identifier>indexed_by</span><span class=special><</span> 801 <span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>name_extractor</span><span class=special>></span> 802 <span class=special>></span> 803<span class=special>></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><</span> 816 <span class=identifier>employee</span> <span class=special>*,</span> 817 <span class=identifier>indexed_by</span><span class=special><</span> 818 <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> 819<span class=special>></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><</span> 832 <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> 833 <span class=identifier>indexed_by</span><span class=special><</span> 834 <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> 835<span class=special>></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<employee></code>,</li> 850 <li><code>std::list<boost::reference_wrapper<employee> >::iterator</code>,</li> 851 <li><code>employee **</code>,</li> 852 <li><code>boost::shared_ptr<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>&);</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>&);</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> key </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<T,int,&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<T,const int,&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<T,int,&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<T,int,&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<const T&,int,&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<T&,int,&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<T></code></td> 934 <td><code>i</code></td> 935 <td><code>member<T,int,&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<T,const int,&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<T,int,&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<T,int,&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<const T&,int,&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<T&,int,&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<const T></code></td> 972 <td><code>i</code></td> 973 <td><code>member<T,const int,&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<T,const int,&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<T,int,&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"> </td> 992</tr> 993<tr> 994 <td><code>gf()</code></td> 995 <td><code>global_fun<const T&,int,&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"> </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<T></code></td> 1007 <td><code>i</code></td> 1008 <td><code>member<T,int,&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<T,const int,&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<T,int,&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<T,int,&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<const T&,int,&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<T&,int,&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<const T></code></td> 1046 <td><code>i</code></td> 1047 <td><code>member<T,const int,&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<T,const int,&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<T,int,&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"> </td> 1066</tr> 1067<tr> 1068 <td><code>gf()</code></td> 1069 <td><code>global_fun<const T&,int,&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"> </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<const T,int,&T::i></code>, but rather as 1106<code>member<T,const int,&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>© Copyright 2003-2020 Joaquín M López Muñ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