generic_programming.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
  2. <html>
  3. <head>
  4. <meta name="generator" content=
  5. "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
  6. <meta http-equiv="Content-Type" content=
  7. "text/html; charset=windows-1252">
  8. <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
  9. <meta name="ProgId" content="FrontPage.Editor.Document">
  10. <title>Generic Programming Techniques</title>
  11. </head>
  12. <body bgcolor="#FFFFFF" text="#000000">
  13. <img src="../boost.png" alt="boost.png (6897 bytes)" align="center"
  14. width="277" height="86">
  15. <h1>Generic Programming Techniques</h1>
  16. <p>This is an incomplete survey of some of the generic programming
  17. techniques used in the <a href="../index.htm">boost</a> libraries.</p>
  18. <h2>Table of Contents</h2>
  19. <ul>
  20. <li><a href="#introduction">Introduction</a></li>
  21. <li><a href="#concept">The Anatomy of a Concept</a></li>
  22. <li><a href="#traits">Traits</a></li>
  23. <li><a href="#tag_dispatching">Tag Dispatching</a></li>
  24. <li><a href="#adaptors">Adaptors</a></li>
  25. <li><a href="#type_generator">Type Generators</a></li>
  26. <li><a href="#object_generator">Object Generators</a></li>
  27. <li><a href="#policy">Policy Classes</a></li>
  28. </ul>
  29. <h2><a name="introduction">Introduction</a></h2>
  30. <p>Generic programming is about generalizing software components so that
  31. they can be easily reused in a wide variety of situations. In C++, class
  32. and function templates are particularly effective mechanisms for generic
  33. programming because they make the generalization possible without
  34. sacrificing efficiency.</p>
  35. <p>As a simple example of generic programming, we will look at how one
  36. might generalize the <tt>memcpy()</tt> function of the C standard
  37. library. An implementation of <tt>memcpy()</tt> might look like the
  38. following:<br>
  39. <br>
  40. </p>
  41. <blockquote>
  42. <pre>
  43. void* memcpy(void* region1, const void* region2, size_t n)
  44. {
  45. const char* first = (const char*)region2;
  46. const char* last = ((const char*)region2) + n;
  47. char* result = (char*)region1;
  48. while (first != last)
  49. *result++ = *first++;
  50. return result;
  51. }
  52. </pre>
  53. </blockquote>
  54. The <tt>memcpy()</tt> function is already generalized to some extent by
  55. the use of <tt>void*</tt> so that the function can be used to copy arrays
  56. of different kinds of data. But what if the data we would like to copy is
  57. not in an array? Perhaps it is in a linked list. Can we generalize the
  58. notion of copy to any sequence of elements? Looking at the body of
  59. <tt>memcpy()</tt>, the function's <b><i>minimal requirements</i></b> are
  60. that it needs to <i>traverse</i> through the sequence using some sort
  61. of pointer, <i>access</i> elements pointed to, <i>write</i> the elements
  62. to the destination, and <i>compare</i> pointers to know when to stop. The
  63. C++ standard library groups requirements such as these into
  64. <b><i>concepts</i></b>, in this case the <a href=
  65. "http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>
  66. concept (for <tt>region2</tt>) and the <a href=
  67. "http://www.sgi.com/tech/stl/OutputIterator.html">Output Iterator</a>
  68. concept (for <tt>region1</tt>).
  69. <p>If we rewrite the <tt>memcpy()</tt> as a function template, and use
  70. the <a href="http://www.sgi.com/tech/stl/InputIterator.html">Input
  71. Iterator</a> and <a href=
  72. "http://www.sgi.com/tech/stl/OutputIterator.html">Output Iterator</a>
  73. concepts to describe the requirements on the template parameters, we can
  74. implement a highly reusable <tt>copy()</tt> function in the following
  75. way:<br>
  76. <br>
  77. </p>
  78. <blockquote>
  79. <pre>
  80. template &lt;typename InputIterator, typename OutputIterator&gt;
  81. OutputIterator
  82. copy(InputIterator first, InputIterator last, OutputIterator result)
  83. {
  84. while (first != last)
  85. *result++ = *first++;
  86. return result;
  87. }
  88. </pre>
  89. </blockquote>
  90. <p>Using the generic <tt>copy()</tt> function, we can now copy elements
  91. from any kind of sequence, including a linked list that exports iterators
  92. such as <tt>std::<a href=
  93. "http://www.sgi.com/tech/stl/List.html">list</a></tt>.<br>
  94. <br>
  95. </p>
  96. <blockquote>
  97. <pre>
  98. #include &lt;list&gt;
  99. #include &lt;vector&gt;
  100. #include &lt;iostream&gt;
  101. int main()
  102. {
  103. const int N = 3;
  104. std::vector&lt;int&gt; region1(N);
  105. std::list&lt;int&gt; region2;
  106. region2.push_back(1);
  107. region2.push_back(0);
  108. region2.push_back(3);
  109. std::copy(region2.begin(), region2.end(), region1.begin());
  110. for (int i = 0; i &lt; N; ++i)
  111. std::cout &lt;&lt; region1[i] &lt;&lt; " ";
  112. std::cout &lt;&lt; std::endl;
  113. }
  114. </pre>
  115. </blockquote>
  116. <h2><a name="concept">Anatomy of a Concept</a></h2>
  117. A <b><i>concept</i></b> is a set of requirements
  118. consisting of valid expressions, associated types, invariants, and
  119. complexity guarantees. A type that satisfies the requirements is
  120. said to <b><i>model</i></b> the concept. A concept can extend the
  121. requirements of another concept, which is called
  122. <b><i>refinement</i></b>.
  123. <ul>
  124. <li><a name="valid_expression"><b>Valid Expressions</b></a> are C++
  125. expressions which must compile successfully for the objects involved in
  126. the expression to be considered <i>models</i> of the concept.</li>
  127. <li><a name="associated_type"><b>Associated Types</b></a> are types
  128. that are related to the modeling type in that they participate in one
  129. or more of the valid expressions. Typically associated types can be
  130. accessed either through typedefs nested within a class definition for
  131. the modeling type, or they are accessed through a <a href=
  132. "#traits">traits class</a>.</li>
  133. <li><b>Invariants</b> are run-time characteristics of the objects that
  134. must always be true, that is, the functions involving the objects must
  135. preserve these characteristics. The invariants often take the form of
  136. pre-conditions and post-conditions.</li>
  137. <li><b>Complexity Guarantees</b> are maximum limits on how long the
  138. execution of one of the valid expressions will take, or how much of
  139. various resources its computation will use.</li>
  140. </ul>
  141. <p>The concepts used in the C++ Standard Library are documented at the <a
  142. href="http://www.sgi.com/tech/stl/table_of_contents.html">SGI STL
  143. site</a>.</p>
  144. <h2><a name="traits">Traits</a></h2>
  145. <p>A traits class provides a way of associating information with a
  146. compile-time entity (a type, integral constant, or address). For example,
  147. the class template <tt><a href=
  148. "http://www.sgi.com/tech/stl/iterator_traits.html">std::iterator_traits&lt;T&gt;</a></tt>
  149. looks something like this:</p>
  150. <blockquote>
  151. <pre>
  152. template &lt;class Iterator&gt;
  153. struct iterator_traits {
  154. typedef ... iterator_category;
  155. typedef ... value_type;
  156. typedef ... difference_type;
  157. typedef ... pointer;
  158. typedef ... reference;
  159. };
  160. </pre>
  161. </blockquote>
  162. The traits' <tt>value_type</tt> gives generic code the type which the
  163. iterator is "pointing at", while the <tt>iterator_category</tt> can be
  164. used to select more efficient algorithms depending on the iterator's
  165. capabilities.
  166. <p>A key feature of traits templates is that they're
  167. <i>non-intrusive</i>: they allow us to associate information with
  168. arbitrary types, including built-in types and types defined in
  169. third-party libraries, Normally, traits are specified for a particular
  170. type by (partially) specializing the traits template.</p>
  171. <p>For an in-depth description of <tt>std::iterator_traits</tt>, see <a
  172. href="http://www.sgi.com/tech/stl/iterator_traits.html">this page</a>
  173. provided by SGI. Another very different expression of the traits idiom in
  174. the standard is <tt>std::numeric_limits&lt;T&gt;</tt> which provides
  175. constants describing the range and capabilities of numeric types.</p>
  176. <h2><a name="tag_dispatching">Tag Dispatching</a></h2>
  177. <p>Tag dispatching is a way of using function overloading to
  178. dispatch based on properties of a type, and is often used hand in
  179. hand with traits classes. A good example of this synergy is the
  180. implementation of the <a href=
  181. "http://www.sgi.com/tech/stl/advance.html"><tt>std::advance()</tt></a>
  182. function in the C++ Standard Library, which increments an iterator
  183. <tt>n</tt> times. Depending on the kind of iterator, there are different
  184. optimizations that can be applied in the implementation. If the iterator
  185. is <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">random
  186. access</a> (can jump forward and backward arbitrary distances), then the
  187. <tt>advance()</tt> function can simply be implemented with <tt>i +=
  188. n</tt>, and is very efficient: constant time. Other iterators must be
  189. <tt>advance</tt>d in steps, making the operation linear in n. If the
  190. iterator is <a href=
  191. "http://www.sgi.com/tech/stl/BidirectionalIterator.html">bidirectional</a>,
  192. then it makes sense for <tt>n</tt> to be negative, so we must decide
  193. whether to increment or decrement the iterator.</p>
  194. <p>The relation between tag dispatching and traits classes is that the
  195. property used for dispatching (in this case the
  196. <tt>iterator_category</tt>) is often accessed through a traits class. The
  197. main <tt>advance()</tt> function uses the <a href=
  198. "http://www.sgi.com/tech/stl/iterator_traits.html"><tt>iterator_traits</tt></a>
  199. class to get the <tt>iterator_category</tt>. It then makes a call the the
  200. overloaded <tt>advance_dispatch()</tt> function. The appropriate
  201. <tt>advance_dispatch()</tt> is selected by the compiler based on whatever
  202. type the <tt>iterator_category</tt> resolves to, either <a href=
  203. "http://www.sgi.com/tech/stl/input_iterator_tag.html"><tt>input_iterator_tag</tt></a>,
  204. <a href=
  205. "http://www.sgi.com/tech/stl/bidirectional_iterator_tag.html"><tt>bidirectional_iterator_tag</tt></a>,
  206. or <a href=
  207. "http://www.sgi.com/tech/stl/random_access_iterator_tag.html"><tt>random_access_iterator_tag</tt></a>.
  208. A <b><i>tag</i></b> is simply a class whose only purpose is to convey
  209. some property for use in tag dispatching and similar techniques. Refer to
  210. <a href="http://www.sgi.com/tech/stl/iterator_tags.html">this page</a>
  211. for a more detailed description of iterator tags.</p>
  212. <blockquote>
  213. <pre>
  214. namespace std {
  215. struct input_iterator_tag { };
  216. struct bidirectional_iterator_tag { };
  217. struct random_access_iterator_tag { };
  218. namespace detail {
  219. template &lt;class InputIterator, class Distance&gt;
  220. void advance_dispatch(InputIterator&amp; i, Distance n, <b>input_iterator_tag</b>) {
  221. while (n--) ++i;
  222. }
  223. template &lt;class BidirectionalIterator, class Distance&gt;
  224. void advance_dispatch(BidirectionalIterator&amp; i, Distance n,
  225. <b>bidirectional_iterator_tag</b>) {
  226. if (n &gt;= 0)
  227. while (n--) ++i;
  228. else
  229. while (n++) --i;
  230. }
  231. template &lt;class RandomAccessIterator, class Distance&gt;
  232. void advance_dispatch(RandomAccessIterator&amp; i, Distance n,
  233. <b>random_access_iterator_tag</b>) {
  234. i += n;
  235. }
  236. }
  237. template &lt;class InputIterator, class Distance&gt;
  238. void advance(InputIterator&amp; i, Distance n) {
  239. typename <b>iterator_traits&lt;InputIterator&gt;::iterator_category</b> category;
  240. detail::advance_dispatch(i, n, <b>category</b>);
  241. }
  242. }
  243. </pre>
  244. </blockquote>
  245. <h2><a name="adaptors">Adaptors</a></h2>
  246. <p>An <i>adaptor</i> is a class template which builds on another type or
  247. types to provide a new interface or behavioral variant. Examples of
  248. standard adaptors are <a href=
  249. "http://www.sgi.com/tech/stl/ReverseIterator.html">std::reverse_iterator</a>,
  250. which adapts an iterator type by reversing its motion upon
  251. increment/decrement, and <a href=
  252. "http://www.sgi.com/tech/stl/stack.html">std::stack</a>, which adapts a
  253. container to provide a simple stack interface.</p>
  254. <p>A more comprehensive review of the adaptors in the standard can be
  255. found <a href="http://portal.acm.org/citation.cfm?id=249118.249120">
  256. here</a>.</p>
  257. <h2><a name="type_generator">Type Generators</a></h2>
  258. <p><b>Note:</b> The <i>type generator</i> concept has largely been
  259. superseded by the more refined notion of a <a href=
  260. "../libs/mpl/doc/refmanual/metafunction.html"><i>metafunction</i></a>. See
  261. <i><a href="http://www.boost-consulting.com/mplbook">C++ Template
  262. Metaprogramming</a></i> for an in-depth discussion of metafunctions.</p>
  263. <p>A <i>type generator</i> is a template whose only purpose is to
  264. synthesize a new type or types based on its template argument(s)<a href=
  265. "#1">[1]</a>. The generated type is usually expressed as a nested typedef
  266. named, appropriately <tt>type</tt>. A type generator is usually used to
  267. consolidate a complicated type expression into a simple one. This example
  268. uses an old version of <tt><a href=
  269. "../libs/iterator/doc/iterator_adaptor.html">iterator_adaptor</a></tt>
  270. whose design didn't allow derived iterator types. As a result, every
  271. adapted iterator had to be a specialization of <tt>iterator_adaptor</tt>
  272. itself and generators were a convenient way to produce those types.</p>
  273. <blockquote>
  274. <pre>
  275. template &lt;class Predicate, class Iterator,
  276. class Value = <i>complicated default</i>,
  277. class Reference = <i>complicated default</i>,
  278. class Pointer = <i>complicated default</i>,
  279. class Category = <i>complicated default</i>,
  280. class Distance = <i>complicated default</i>
  281. &gt;
  282. struct filter_iterator_generator {
  283. typedef iterator_adaptor&lt;
  284. Iterator,filter_iterator_policies&lt;Predicate,Iterator&gt;,
  285. Value,Reference,Pointer,Category,Distance&gt; <b>type</b>;
  286. };
  287. </pre>
  288. </blockquote>
  289. <p>Now, that's complicated, but producing an adapted filter iterator
  290. using the generator is much easier. You can usually just write:</p>
  291. <blockquote>
  292. <pre>
  293. boost::filter_iterator_generator&lt;my_predicate,my_base_iterator&gt;::type
  294. </pre>
  295. </blockquote>
  296. <h2><a name="object_generator">Object Generators</a></h2>
  297. <p>An <i>object generator</i> is a function template whose only purpose
  298. is to construct a new object out of its arguments. Think of it as a kind
  299. of generic constructor. An object generator may be more useful than a
  300. plain constructor when the exact type to be generated is difficult or
  301. impossible to express and the result of the generator can be passed
  302. directly to a function rather than stored in a variable. Most Boost
  303. object generators are named with the prefix "<tt>make_</tt>", after
  304. <tt>std::<a href=
  305. "http://www.sgi.com/tech/stl/pair.html">make_pair</a>(const&nbsp;T&amp;,&nbsp;const&nbsp;U&amp;)</tt>.</p>
  306. <p>For example, given:</p>
  307. <blockquote>
  308. <pre>
  309. struct widget {
  310. void tweak(int);
  311. };
  312. std::vector&lt;widget *&gt; widget_ptrs;
  313. </pre>
  314. </blockquote>
  315. By chaining two standard object generators, <tt>std::<a href=
  316. "http://www.dinkumware.com/htm_cpl/functio2.html#bind2nd">bind2nd</a>()</tt>
  317. and <tt>std::<a href=
  318. "http://www.dinkumware.com/htm_cpl/functio2.html#mem_fun">mem_fun</a>()</tt>,
  319. we can easily tweak all widgets:
  320. <blockquote>
  321. <pre>
  322. void tweak_all_widgets1(int arg)
  323. {
  324. for_each(widget_ptrs.begin(), widget_ptrs.end(),
  325. <b>bind2nd</b>(std::<b>mem_fun</b>(&amp;widget::tweak), arg));
  326. }
  327. </pre>
  328. </blockquote>
  329. <p>Without using object generators the example above would look like
  330. this:</p>
  331. <blockquote>
  332. <pre>
  333. void tweak_all_widgets2(int arg)
  334. {
  335. for_each(struct_ptrs.begin(), struct_ptrs.end(),
  336. <b>std::binder2nd&lt;std::mem_fun1_t&lt;void, widget, int&gt; &gt;</b>(
  337. std::<b>mem_fun1_t&lt;void, widget, int&gt;</b>(&amp;widget::tweak), arg));
  338. }
  339. </pre>
  340. </blockquote>
  341. <p>As expressions get more complicated the need to reduce the verbosity
  342. of type specification gets more compelling.</p>
  343. <h2><a name="policy">Policy Classes</a></h2>
  344. <p>A policy class is a template parameter used to transmit behavior. An
  345. example from the standard library is <tt>std::<a href=
  346. "http://www.dinkumware.com/htm_cpl/memory.html#allocator">allocator</a></tt>,
  347. which supplies memory management behaviors to standard <a href=
  348. "http://www.sgi.com/tech/stl/Container.html">containers</a>.</p>
  349. <p>Policy classes have been explored in detail by <a href=
  350. "http://www.moderncppdesign.com/">Andrei Alexandrescu</a> in <a href=
  351. "http://www.informit.com/articles/article.asp?p=167842">this chapter</a>
  352. of his book, <i>Modern C++ Design</i>. He writes:</p>
  353. <blockquote>
  354. <p>In brief, policy-based class design fosters assembling a class with
  355. complex behavior out of many little classes (called policies), each of
  356. which takes care of only one behavioral or structural aspect. As the
  357. name suggests, a policy establishes an interface pertaining to a
  358. specific issue. You can implement policies in various ways as long as
  359. you respect the policy interface.</p>
  360. <p>Because you can mix and match policies, you can achieve a
  361. combinatorial set of behaviors by using a small core of elementary
  362. components.</p>
  363. </blockquote>
  364. <p>Andrei's description of policy classes suggests that their power is
  365. derived from granularity and orthogonality. Less-granular policy
  366. interfaces have been shown to work well in practice, though. <a href=
  367. "http://cvs.sourceforge.net/viewcvs.py/*checkout*/boost/boost/libs/utility/Attic/iterator_adaptors.pdf">
  368. This paper</a> describes an old version of <tt><a href=
  369. "../libs/iterator/doc/iterator_adaptor.html">iterator_adaptor</a></tt>
  370. that used non-orthogonal policies. There is also precedent in the
  371. standard library: <tt><a href=
  372. "http://www.dinkumware.com/htm_cpl/string2.html#char_traits">std::char_traits</a></tt>,
  373. despite its name, acts as a policies class that determines the behaviors
  374. of <a href=
  375. "http://www.dinkumware.com/htm_cpl/string2.html#basic_string">std::basic_string</a>.</p>
  376. <h2>Notes</h2>
  377. <a name="1">[1]</a> Type generators are sometimes viewed as a workaround
  378. for the lack of ``templated typedefs'' in C++.
  379. <hr>
  380. <p>Revised
  381. <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->18
  382. August 2004<!--webbot bot="Timestamp" endspan i-checksum="14885" -->
  383. </p>
  384. <p>&copy; Copyright David Abrahams 2001. Permission to copy, use, modify,
  385. sell and distribute this document is granted provided this copyright
  386. notice appears in all copies. This document is provided "as is" without
  387. express or implied warranty, and with no claim as to its suitability for
  388. any purpose.
  389. <!-- LocalWords: HTML html charset gif alt htm struct SGI namespace std libs
  390. -->
  391. <!-- LocalWords: InputIterator BidirectionalIterator RandomAccessIterator pdf
  392. -->
  393. <!-- LocalWords: typename Alexandrescu templated Andrei's Abrahams memcpy int
  394. -->
  395. <!-- LocalWords: const OutputIterator iostream pre cpl
  396. -->
  397. </p>
  398. </body>
  399. </html>
粤ICP备19079148号