generic_programming.html 18 KB

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