generic_programming.html 18 KB

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