summaryrefslogtreecommitdiff
path: root/more/generic_programming.html
blob: 9cd5d80342dc54eca97354f90b38f0b6bb6b168c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">

    <meta name="generator" content="HTML Tidy, see www.w3.org">
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
    <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
    <meta name="ProgId" content="FrontPage.Editor.Document">

    <title>Generic Programming Techniques</title>

    <img src="../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
    width="277" height="86"> 

    <body bgcolor="#FFFFFF" text="#000000">

    <h1>Generic Programming Techniques</h1>

    <p>This is an incomplete survey of some of the generic programming
    techniques used in the <a href="../index.htm">boost</a> libraries.

    <h2>Table of Contents</h2>

    <ul>
      <li><a href="#introduction">Introduction</a>

      <li><a href="#concept">The Anatomy of a Concept</a>

      <li><a href="#traits">Traits</a>

      <li><a href="#tag_dispatching">Tag Dispatching</a>

      <li><a href="#adaptors">Adaptors</a>

      <li><a href="#type_generator">Type Generators</a>

      <li><a href="#object_generator">Object Generators</a>

      <li><a href="#policy">Policy Classes</a>
    </ul>

    <h2><a name="introduction">Introduction</a></h2>

    <p>Generic programming is about generalizing software components so that
    they can be easily reused in a wide variety of situations. In C++, class
    and function templates are particularly effective mechanisms for generic
    programming because they make the generalization possible without
    sacrificing efficiency.

    <p>As a simple example of generic programming, we will look at how one
    might generalize the <tt>memcpy()</tt> function of the C standard library.
    An implementation of <tt>memcpy()</tt> might look like the following:
    <br>
    <br>

    <blockquote>
<pre>
void* memcpy(void* region1, const void* region2, size_t n)
{
  const char* first = (const char*)region2;
  const char* last = ((const char*)region2) + n;
  char* result = (char*)region1;
  while (first != last)
    *result++ = *first++;
  return result;
}
</pre>
    </blockquote>
    The <tt>memcpy()</tt> function is already generalized to some extent by the
    use of <tt>void*</tt> so that the function can be used to copy arrays of
    different kinds of data. But what if the data we would like to copy is not
    in an array? Perhaps it is in a linked list. Can we generalize the notion
    of copy to any sequence of elements? Looking at the body of
    <tt>memcpy()</tt>, the function's <b><i>minimal requirements</i></b> are
    that it needs to to <i>traverse</i> through the sequence using some sort of
    pointer, <i>access</i> elements pointed to, <i>write</i> the elements to
    the destination, and <i>compare</i> pointers to know when to stop. The C++
    standard library groups requirements such as these into
    <b><i>concepts</i></b>, in this case the <a href=
    "http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a> concept
    (for <tt>region2</tt>) and the <a href=
    "http://www.sgi.com/tech/stl/OutputIterator.html">Output Iterator</a>
    concept (for <tt>region1</tt>). 

    <p>If we rewrite the <tt>memcpy()</tt> as a function template, and use the
    <a href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>
    and <a href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
    Iterator</a> concepts to describe the requirements on the template
    parameters, we can implement a highly reusable <tt>copy()</tt> function in
    the following way:
    <br>
    <br>

    <blockquote>
<pre>
template &lt;typename InputIterator, typename OutputIterator&gt;
OutputIterator
copy(InputIterator first, InputIterator last, OutputIterator result)
{
  while (first != last)
    *result++ = *first++;
  return result;
}
</pre>
    </blockquote>

    <p>Using the generic <tt>copy()</tt> function, we can now copy elements
    from any kind of sequence, including a linked list that exports iterators
    such as <tt>std::<a href=
    "http://www.sgi.com/tech/stl/List.html">list</a></tt>.
    <br>
    <br>

    <blockquote>
<pre>
#include &lt;list&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;

int main()
{
  const int N = 3;
  std::vector&lt;int&gt; region1(N);
  std::list&lt;int&gt; region2;

  region2.push_back(1);
  region2.push_back(0);
  region2.push_back(3);
  
  std::copy(region2.begin(), region2.end(), region1.begin());

  for (int i = 0; i &lt; N; ++i)
    std::cout &lt;&lt; region1[i] &lt;&lt; " ";
  std::cout &lt;&lt; std::endl;
}
</pre>
    </blockquote>

    <h2><a name="concept">Anatomy of a Concept</a></h2>
    A <b><i>concept</i></b> is a set requirements, where the requirements
    consist of valid expressions, associated types, invariants, and complexity
    guarantees. A type that satisfies the set of requirements is said to
    <b><i>model</i></b> the concept. A concept can extend the requirements of
    another concept, which is called <b><i>refinement</i></b>. 

    <ul>
      <li><a name="valid_expression"><b>Valid Expressions</b></a> are C++
      expressions which must compile successfully for the objects involved in
      the expression to be considered <i>models</i> of the concept.

      <li><a name="associated_type"><b>Associated Types</b></a> are types that
      are related to the modeling type in that they participate in one or more
      of the valid expressions. Typically associated types can be accessed
      either through typedefs nested within a class definition for the modeling
      type, or they are accessed through a <a href="#traits">traits class</a>.

      <li><b>Invariants</b> are run-time characteristics of the objects that
      must always be true, that is, the functions involving the objects must
      preserve these characteristics. The invariants often take the form of
      pre-conditions and post-conditions.

      <li><b>Complexity Guarantees</b> are maximum limits on how long the
      execution of one of the valid expressions will take, or how much of
      various resources its computation will use.
    </ul>

    <p>The concepts used in the C++ Standard Library are documented at the <a
    href="http://www.sgi.com/tech/stl/table_of_contents.html">SGI STL site</a>.

    <h2><a name="traits">Traits</a></h2>

    <p>A traits class provides a way of associating information with a
    compile-time entity (a type, integral constant, or address). For example,
    the class template <tt><a href=
    "http://www.sgi.com/tech/stl/iterator_traits.html">std::iterator_traits&lt;T&gt;</a></tt>
    looks something like this:

    <blockquote>
<pre>
template &lt;class Iterator&gt;
struct iterator_traits {
  typedef ... iterator_category;
  typedef ... value_type;
  typedef ... difference_type;
  typedef ... pointer;
  typedef ... reference;
};
</pre>
    </blockquote>
    The traits' <tt>value_type</tt> gives generic code the type which the
    iterator is "pointing at", while the <tt>iterator_category</tt> can be used
    to select more efficient algorithms depending on the iterator's
    capabilities. 

    <p>A key feature of traits templates is that they're <i>non-intrusive</i>:
    they allow us to associate information with arbitrary types, including
    built-in types and types defined in third-party libraries, Normally, traits
    are specified for a particular type by (partially) specializing the traits
    template.

    <p>For an in-depth description of <tt>std::iterator_traits</tt>, see <a
    href="http://www.sgi.com/tech/stl/iterator_traits.html">this page</a>
    provided by SGI. Another very different expression of the traits idiom in
    the standard is <tt>std::numeric_limits&lt;T&gt;</tt> which provides
    constants describing the range and capabilities of numeric types.

    <h2><a name="tag_dispatching">Tag Dispatching</a></h2>

    <p>A technique that often goes hand in hand with traits classes is tag
    dispatching, which is a way of using function overloading to dispatch based
    on properties of a type. A good example of this is the implementation of the
    <a href=
    "http://www.sgi.com/tech/stl/advance.html"><tt>std::advance()</tt></a>
    function in the C++ Standard Library, which increments an iterator
    <tt>n</tt> times. Depending on the kind of iterator, there are different
    optimizations that can be applied in the implementation. If the iterator is
    <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">random
    access</a> (can jump forward and backward arbitrary distances), then the
    <tt>advance()</tt> function can simply be implemented with <tt>i += n</tt>,
    and is very efficient: constant time. Other iterators must be
    <tt>advance</tt>d in steps, making the operation linear in n. If the
    iterator is <a href=
    "http://www.sgi.com/tech/stl/BidirectionalIterator.html">bidirectional</a>,
    then it makes sense for <tt>n</tt> to be negative, so we must decide whether
    to increment or decrement the iterator.

    <p>The relation between tag dispatching and traits classes is that the
    property used for dispatching (in this case the <tt>iterator_category</tt>)
    is often accessed through a traits class. The main <tt>advance()</tt> function
    uses the <a href=
    "http://www.sgi.com/tech/stl/iterator_traits.html"><tt>iterator_traits</tt></a>
    class to get the <tt>iterator_category</tt>. It then makes a call the the
    overloaded <tt>advance_dispatch()</tt> function. The appropriate
    <tt>advance_dispatch()</tt> is selected by the compiler based on whatever
    type the <tt>iterator_category</tt> resolves to, either <a href=
    "http://www.sgi.com/tech/stl/input_iterator_tag.html"><tt>input_iterator_tag</tt></a>,
    <a href=
    "http://www.sgi.com/tech/stl/bidirectional_iterator_tag.html"><tt>bidirectional_iterator_tag</tt></a>,
    or <a href=
    "http://www.sgi.com/tech/stl/random_access_iterator_tag.html"><tt>random_access_iterator_tag</tt></a>.
    A <b><i>tag</i></b> is simply a class whose only purpose is to convey some
    property for use in tag dispatching and similar techniques. Refer to <a
    href="http://www.sgi.com/tech/stl/iterator_tags.html">this page</a> for a
    more detailed description of iterator tags.

    <blockquote>
<pre>
namespace std {
  struct input_iterator_tag { };
  struct bidirectional_iterator_tag { };
  struct random_access_iterator_tag { };

  namespace detail {
    template &lt;class InputIterator, class Distance&gt;
    void advance_dispatch(InputIterator&amp; i, Distance n, <b>input_iterator_tag</b>) {
      while (n--) ++i;
    }

    template &lt;class BidirectionalIterator, class Distance&gt;
    void advance_dispatch(BidirectionalIterator&amp; i, Distance n, 
       <b>bidirectional_iterator_tag</b>) {
      if (n &gt;= 0)
        while (n--) ++i;
      else
        while (n++) --i;
    }

    template &lt;class RandomAccessIterator, class Distance&gt;
    void advance_dispatch(RandomAccessIterator&amp; i, Distance n, 
       <b>random_access_iterator_tag</b>) {
      i += n;
    }
  }

  template &lt;class InputIterator, class Distance&gt;
  void advance(InputIterator&amp; i, Distance n) {
    typename <b>iterator_traits&lt;InputIterator&gt;::iterator_category</b> category;
    detail::advance_dispatch(i, n, <b>category</b>);
  }
}
</pre>
    </blockquote>

    <h2><a name="adaptors">Adaptors</a></h2>

    <p>An <i>adaptor</i> is a class template which builds on another type or
    types to provide a new interface or behavioral variant. Examples of
    standard adaptors are <a href=
    "http://www.sgi.com/tech/stl/ReverseIterator.html">std::reverse_iterator</a>,
    which adapts an iterator type by reversing its motion upon
    increment/decrement, and <a href=
    "http://www.sgi.com/tech/stl/stack.html">std::stack</a>, which adapts a
    container to provide a simple stack interface.

    <p>A more comprehensive review of the adaptors in the standard can be found
    <a href=
    "http://www.cs.rpi.edu/~wiseb/xrds/ovp2-3b.html#SECTION00015000000000000000">
    here</a>.

    <h2><a name="type_generator">Type Generators</a></h2>

    <p>A <i>type generator</i> is a template whose only purpose is to
    synthesize a new type or types based on its template argument(s)<a href=
    "#1">[1]</a>. The generated type is usually expressed as a nested typedef
    named, appropriately <tt>type</tt>. A type generator is usually used to
    consolidate a complicated type expression into a simple one, as in
    <tt>boost::<a href=
    "../libs/utility/filter_iterator.htm">filter_iterator_generator</a></tt>,
    which looks something like this:

    <blockquote>
<pre>
template &lt;class Predicate, class Iterator, 
    class Value = <i>complicated default</i>,
    class Reference = <i>complicated default</i>,
    class Pointer = <i>complicated default</i>,
    class Category = <i>complicated default</i>,
    class Distance = <i>complicated default</i>
         &gt;
struct filter_iterator_generator {
    typedef iterator_adaptor&lt;
        Iterator,filter_iterator_policies&lt;Predicate,Iterator&gt;,
        Value,Reference,Pointer,Category,Distance&gt; <b>type</b>;
};
</pre>
    </blockquote>

    <p>Now, that's complicated, but producing an adapted filter iterator is
    much easier. You can usually just write:

    <blockquote>
<pre>
boost::filter_iterator_generator&lt;my_predicate,my_base_iterator&gt;::type
</pre>
    </blockquote>

    <h2><a name="object_generator">Object Generators</a></h2>

    <p>An <i>object generator</i> is a function template whose only purpose is
    to construct a new object out of its arguments. Think of it as a kind of
    generic constructor. An object generator may be more useful than a plain
    constructor when the exact type to be generated is difficult or impossible
    to express and the result of the generator can be passed directly to a
    function rather than stored in a variable. Most Boost object generators are
    named with the prefix "<tt>make_</tt>", after <tt>std::<a href=
    "http://www.sgi.com/tech/stl/pair.html">make_pair</a>(const T&amp;, const U&amp;)</tt>.

    <p>For example, given:

    <blockquote>
<pre>
struct widget {
  void tweak(int);
};
std::vector&lt;widget *&gt; widget_ptrs;
</pre>
    </blockquote>
    By chaining two standard object generators, <tt>std::<a href=
    "http://www.dinkumware.com/htm_cpl/functio2.html#bind2nd">bind2nd</a>()</tt>
    and <tt>std::<a href=
    "http://www.dinkumware.com/htm_cpl/functio2.html#mem_fun">mem_fun</a>()</tt>,
    we can easily tweak all widgets: 

    <blockquote>
<pre>
void tweak_all_widgets1(int arg)
{
   for_each(widget_ptrs.begin(), widget_ptrs.end(),
      <b>bind2nd</b>(std::<b>mem_fun</b>(&amp;widget::tweak), arg));
}
</pre>
    </blockquote>

    <p>Without using object generators the example above would look like this:

    <blockquote>
<pre>
void tweak_all_widgets2(int arg)
{
   for_each(struct_ptrs.begin(), struct_ptrs.end(),
      <b>std::binder2nd&lt;std::mem_fun1_t&lt;void, widget, int&gt; &gt;</b>(
          std::<b>mem_fun1_t&lt;void, widget, int&gt;</b>(&amp;widget::tweak), arg));
}
</pre>
    </blockquote>

    <p>As expressions get more complicated the need to reduce the verbosity of
    type specification gets more compelling.

    <h2><a name="policy">Policy Classes</a></h2>

    <p>A policy class is a template parameter used to transmit behavior. An
    example from the standard library is <tt>std::<a href=
    "http://www.dinkumware.com/htm_cpl/memory.html#allocator">allocator</a></tt>,
    which supplies memory management behaviors to standard <a href=
    "http://www.sgi.com/tech/stl/Container.html">containers</a>.

    <p>Policy classes have been explored in detail by <a href=
    "mailto:andrewalex@hotmail.com">Andrei Alexandrescu</a> in <a href=
    "http://www.cs.ualberta.ca/~hoover/cmput401/XP-Notes/xp-conf/Papers/7_3_Alexandrescu.pdf">
    this paper</a>. He writes:

    <blockquote>
      <p>Policy classes are implementations of punctual design choices. They
      are inherited from, or contained within, other classes. They provide
      different strategies under the same syntactic interface. A class using
      policies is templated having one template parameter for each policy it
      uses. This allows the user to select the policies needed.

      <p>The power of policy classes comes from their ability to combine
      freely. By combining several policy classes in a template class with
      multiple parameters, one achieves combinatorial behaviors with a linear
      amount of code.
    </blockquote>

    <p>Andrei's description of policy classes describe their power as being
    derived from their granularity and orthogonality. Boost has probably
    diluted the distinction in the <a href=
    "../libs/utility/iterator_adaptors.htm">Iterator Adaptors</a> library,
    where we transmit all of an adapted iterator's behavior in a single policy
    class. There is precedent for this, however: <tt><a href=
    "http://www.dinkumware.com/htm_cpl/string2.html#char_traits">std::char_traits</a></tt>,
    despite its name, acts as a policies class that determines the behaviors of
    <a href=
    "http://www.dinkumware.com/htm_cpl/string2.html#basic_string">std::basic_string</a>.

    <h2>Notes</h2>
    <a name="1">[1]</a> Type generators are a workaround for the lack of
    ``templated typedefs'' in C++. 
    <hr>

    <p>Revised 
    <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->14 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14885" -->


    <p>&copy; Copyright David Abrahams 2001. Permission to copy, use, modify,
    sell and distribute this document is granted provided this copyright notice
    appears in all copies. This document is provided "as is" without express or
    implied warranty, and with no claim as to its suitability for any purpose. 
    <!--  LocalWords:  HTML html charset gif alt htm struct SGI namespace std libs
     -->
    <!--  LocalWords:  InputIterator BidirectionalIterator RandomAccessIterator pdf
     -->
    <!--  LocalWords:  typename Alexandrescu templated Andrei's Abrahams memcpy int
     -->

    <!--  LocalWords:  const OutputIterator iostream pre cpl
     -->

     </body>