    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Choosing Template Parameters</title>
        <link>https://members.accu.org/index.php/articles/325</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + Overload Journal #58 - Dec 2003</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c154/">58</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-154/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+154/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Choosing Template Parameters</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 02 December 2003 21:55:55 +00:00 or Tue, 02 December 2003 21:55:55 +00:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e18" id="d0e18"></a></h2>
</div>
<p>Choosing the right parameters for a template can make a
significant difference to how useful the template is. In this
article, I will present a very simple guideline that, where
applicable, can improve a template's flexibility. I will also
provide an example of how the standard library itself could have
applied this guideline but didn't.</p>
<p>The fundamental idea can be seen in the following example:</p>
<pre class="programlisting">
template&lt;typename Element&gt;
struct inflexible {
  typedef Element element_t;
  typedef std::vector&lt;Element&gt; container_t;
  // ...
};

template&lt;typename Container&gt;
struct flexible {
  typedef typename Container::value_type
                              element_t;
  typedef Container container_t;
  // ...
};
</pre>
<p>These two templates both define two member typedefs <span class=
"type">element_t</span> and <span class="type">container_t</span>,
presumably for further use internally (not shown). In the first
case, although the template can have any element type, it always
uses a <tt class="classname">std::vector</tt> as container. The
second case is more flexible, since it will work with any
container, and any element type, provided that the container has a
sufficiently vector-like interface. The principle at work can be
stated as follows:</p>
<div class="blockquote">
<blockquote class="blockquote">
<p>&quot;A template will be more flexible if, instead of internally
generating a new type from its arguments, it accepts the generated
type directly as a parameter.&quot;</p>
</blockquote>
</div>
<p>Unfortunately, there are some costs associated with this
approach, which I will point out first before expanding on the
benefits. Firstly, the interface may be less convenient. From the
example, client code would have to use <span class=
"type">flexible&lt;std::vector&lt;int&gt; &gt;</span> instead of
simply <span class="type">inflexible&lt;int&gt;</span>. There is an
easy solution, which is to provide a convenient interface once the
more flexible implementation is available:</p>
<pre class="programlisting">
template &lt;typename Element&gt;
struct convenient :
               flexible&lt;std::vector&lt;Element&gt; &gt; {
};
</pre>
<p>The second cost is that the documentation for the template will
be more complicated. In the example, instead of merely specifying
the constraints on the element type, the documentation must now
also describe what interface the container type must provide, such
as an <tt class="function">operator[]</tt> member function, insert
functions and so on. Ideally, the requirements would also be broad
enough to allow for future changes in the implementation of the
template, for instance switching internally from using <tt class=
"function">operator[]</tt> to random-access iterators.</p>
<p>Lastly, to inter-operate with a wide variety of argument types,
the template implementation will need to be more carefully written.
In the example, instead of assuming that <span class=
"type">size_t</span> is the correct type for indexing into the
container, the implementation should use typename <span class=
"type">container_t::size_type</span>.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e66" id="d0e66"></a>A Familiar
Example</h2>
</div>
<p>To see the consequences of writing a more flexible template,
let's take a look at <tt class="classname">std::map</tt>:</p>
<pre class="programlisting">
template &lt;class Key, class T, ...&gt;
class map {
public:
  typedef Key key_type;
  typedef T mapped_type;
  typedef pair&lt;const Key, T&gt; value_type;
  // ...
};
</pre>
<p>This should be recognizable as a variant of the first template
/<tt class="classname">inflexible</tt>/, since it generates the
<span class="type">value_type</span> (using <tt class=
"classname">std::pair</tt>) from template arguments instead of
accepting a <i class="parameter"><tt>value_type</tt></i> parameter
directly. If I have a user-defined type that has both <tt class=
"varname">key_type</tt> and <tt class="varname">mapped_type</tt> in
the same object, I have a problem which will be familiar to some
readers from their own experience. For example:</p>
<pre class="programlisting">
struct person {
  person_id_t m_person_id; //Unique identifier
  std::string m_surname;
  std::string m_other_names;
  // ...
};

void foo () {
  typedef std::map&lt;person_id_t, person&gt; map_t;
  map_t my_map;
  person p;
  person_id_t id;

  // must generate a pair object for insertion
  my_map.insert(map_t::value_type
                (p.m_person_id, p));

  // lookup by ID and modification are
  // convenient
  my_map[id].m_other_names = &quot;Joe&quot;;
}
</pre>
<p>The insertion is a little cumbersome, and duplicates the person
ID for every entry in the map. How much of a problem this is in
practice depends on the nature of the key type in use, but it is
usually a good idea to avoid data duplication where possible.
Alternatively, one could choose to use <tt class=
"classname">std::set</tt> and have code like this:</p>
<pre class="programlisting">
struct person_id_less {
  bool operator()(person const &amp;p1,
                  person const &amp;p2) {
    return p1.m_person_id &lt; p2.m_person_id;
  }
};

void foo () {
  typedef std::set&lt;person, person_id_less&gt; set_t;
  set_t my_set;
  person p;
  person_id_t id;

  // insertion is convenient
  my_set.insert (p);
 
  // find requires a person object instead
  // of just the ID
  p.m_person_id = id;

  // mutable access requires a const_cast
  const_cast&lt;person &amp;&gt;(
            *my_set.find (p)).m_other_names = &quot;Joe&quot;;
}
</pre>
<p>So <tt class="classname">std::set</tt> is easier to use as far
as insertions are concerned, and does not duplicate any data, but
element lookup and modification are made more difficult. In fact,
the <tt class="classname">std::set</tt> example has a potentially
catastrophic problem, since <tt class="function">my_set.find()</tt>
will return <tt class="function">my_set.end()</tt> if there is no
match, leading to undefined behaviour from the code. None of these
problems are insurmountable, but they do reveal some limitations of
the two templates' interfaces.</p>
<p>Now consider an alternative template, <tt class=
"classname">map2</tt>, which applies this article's guideline by
accepting the complete value type as a template parameter:</p>
<pre class="programlisting">
template &lt;class Value, ...&gt;
class map2 {
public:
  typedef typename Value::first_type key_type;
  typedef typename Value::second_type mapped_type;
  typedef Value value_type;
  // ...
};
</pre>
<p>This template assumes that the supplied type provides the same
interface as <tt class="classname">std::pair</tt>, which means that
the map implementation needs almost no changes at all.
Unfortunately, this also means that the supplied type must have
public member variables first and second which contain the object's
key and mapped value, respectively. So allowing the client to
provide different value types, but requiring a matching interface,
hasn't actually achieved very much in this case.</p>
<p>Of course, we don't have to stop there. Having made the decision
to accept value types other than instances of <tt class=
"classname">std::pair</tt>, it is fairly natural to consider
alternative interfaces. For instance, requiring that the value type
provide member functions <tt class="function">get_key</tt> and
<tt class="function">get_mapped</tt> would solve most of the
problems. It would then be relatively easy to extend the person
class to provide the necessary interface and store <tt class=
"classname">person</tt> objects directly in a <tt class=
"classname">map2</tt>.</p>
<p>Unfortunately, this assumes that the value type knows in advance
that it is going to be stored in a map. Furthermore, it is not very
convenient for user defined types that could appear in different
maps with different keys (e.g. <tt class=
"varname">person::m_surname</tt> would be suitable as an
alternative multimap key). A far better solution would be to accept
some additional information via a traits class:</p>
<pre class="programlisting">
template &lt;class Traits, ...&gt;
class map3 {
public:
  typedef typename Traits::key_type key_type;
  typedef typename Traits::mapped_type mapped_type;
  typedef typename Traits::value_type value_type;
  // ...
};

struct person_id_traits {
  typedef person_id_t key_type;
  typedef person mapped_type;
  typedef person value_type;
  static key_type const &amp;get_key(
                  value_type const &amp;val) {
    return val.m_person_id;
  }
  static mapped_type &amp;get_mapped(
                  value_type &amp;val) {
    return val;
  }
  static value_type construct(
                  key_type const &amp;key) {
    // Required by map3::operator[]
    return value_type (key);
  }
};

void foo () {
  // person has an unchanged interface
  typedef map3&lt;person_id_traits&gt; map_t;
  map_t my_map;
  person p;
  person_id_t id;
  // insertion is convenient
  my_map.insert (p);
  // lookup by ID and modification are
  // convenient
  my_map[id].m_other_names = &quot;Joe&quot;;
}
</pre>
<p>This template provides convenient interfaces for insertion,
lookup and modification. It avoids any data duplication and
compares well to the <tt class="classname">std::map</tt> and
<tt class="classname">std::set</tt> versions, which each made some
of the operations simple but not others.</p>
<p>Before going on, the construct function in the traits class
probably requires further explanation. It is necessary because the
<tt class="classname">map3</tt> <tt class=
"function">operator[]</tt> accepts just a key as parameter and
might have to insert a whole new value into the map. The <tt class=
"classname">std::map</tt> template has a similar constraint, since
it defines <tt class="function">operator[]</tt> in terms of
<tt class="function">insert(make_pair(key, T()))</tt>, requiring
that its parameter <span class="type">T</span> be default
constructible. This is also quite similar to the lookup problem
mentioned for <tt class="classname">std::set</tt>, which requires a
complete value object in order to search the container. The
advantage of <tt class="classname">map</tt> (or <tt class=
"classname">map3</tt>) is that this problem only arises in
<tt class="function">operator[]</tt> and not the alternative find
member function.</p>
<p>So the traits-based version provides a good solution, because it
means that almost any class can be stored in the <tt class=
"classname">map3</tt> container without internal changes. There is
some work involved in writing a new traits class every time, but it
is easy enough to emulate the original <tt class=
"classname">std::map</tt> interface for the simple cases that it
conveniently supports:</p>
<pre class="programlisting">
template&lt;typename Key, typename T&gt;
struct std_map_traits {
  typedef Key key_type;
  typedef T mapped_type;
  typedef std::pair&lt;Key const, T&gt; value_type;

  static key_type const &amp;get_key(
                      value_type const &amp;val) {
    return val.first;
  }

  static mapped_type &amp;get_mapped(
                      value_type &amp;val) {
    return val.second;
  }

  static value_type construct(
                      key_type const &amp;key) {
    // Required by map3::operator[]
    return value_type (key, mapped_type());
  }
};

template&lt;typename Key, typename T, ...&gt;
struct std_map :
           map3&lt;std_map_traits&lt;Key, T&gt;, ...&gt; {
  // constructors...
};

void bar () {
  std_map&lt;int, std::string&gt; my_map;
  my_map[1] = &quot;hello&quot;;
}
</pre>
<p>There are plenty of other applications for a more flexible map.
For instance, suppose that we want two different indexes for the
same collection of person objects, one which uses the (unique)
person ID, and another which uses the (non-unique) surname. A
sensible way to do this is to use a reference-counted smart
pointer, and maintain two sets of pointers that are sorted by the
alternative keys. In our case, client code can re-use its existing
traits classes by writing a traits pointer-adaptor template. For
example (using the boost reference counted pointer available free
from <a href="http://www.boost.org" target=
"_top">http://www.boost.org</a>):</p>
<pre class="programlisting">
// Adaptor to convert a traits class for use
// via a map3 of boost::shared_ptr values

template&lt;typename PlainTraits&gt;
struct ptr_traits {
private:
  typedef typename PlainTraits::value_type plain_value_type;
public:
  typedef typename PlainTraits::key_type key_type;
  typedef typename PlainTraits::mapped_type mapped_type;
  typedef boost::shared_ptr&lt;plain_value_type&gt; value_type;

  static key_type const &amp;get_key(
                            value_type const &amp;val) {
    return PlainTraits::get_key(*val);
  }

  static mapped_type &amp;get_mapped(
                            value_type &amp;val) {
    return PlainTraits::get_mapped (*val);
  }

  static value_type construct(
                           key_type const &amp;key) {
    return value_type(
      new plain_value_type(
        PlainTraits::construct(key)));
  }
};

// Define two pointer-based indexes using
// different keys
map3 &lt;ptr_traits &lt;person_id_traits&gt; &gt; index1;
multimap3 &lt;ptr_traits &lt;person_name_traits&gt; &gt; index2;

// ...
index1[my_id].m_other_names = &quot;Joe&quot;;
</pre>
<p>Note that the fact that the indexes store reference-counted
pointers internally is at least partially hidden from the client
code. This is not a complete solution, of course, but goes some way
towards one (interested readers may also like to investigate the
link given under additional reading). An alternative solution using
<tt class="classname">std::set</tt> would also be possible, but
again is not quite as convenient for searching and modifying. Even
ignoring the possibility of <tt class="function">find()</tt>
returning <tt class="function">end()</tt>, the assignment from
above would look more like this:</p>
<pre class="programlisting">
boost::shared_ptr&lt;person&gt; temp(
                            new person (my_id));
(*my_set.find (temp))-&gt;m_other_names = &quot;Joe&quot;;
</pre>
<p>In the <tt class="classname">map3</tt> solution from above,
these details are effectively encapsulated the <tt class=
"classname">ptr_traits</tt> template.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e233" id=
"d0e233"></a>Conclusions</h2>
</div>
<p>In the case of <tt class="classname">std::map</tt>, a number of
changes were necessary to achieve a real gain in flexibility.
However, the first step was to allow the client code to choose
their own value type. It is then a fairly obvious improvement to
access the keys and mapped values via client-provided functions
instead of by using member variables. In this case, a traits class
is a convenient way to provide the necessary additional
information.</p>
<p>More generally, whenever a template internally generates a new
type from its arguments, it is limiting its own flexibility. By
accepting the generated type as a parameter instead, the template
can become flexible not only in terms of the original parameters,
but also in the choice of generated type. There are certain
trade-offs in terms of ease of documentation and coding, but
potential users of the template may discover unexpected benefits
from a more flexible template.</p>
<p>Thanks to Phil Bass for his comments on two earlier drafts of
this article.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e245" id="d0e245"></a>Additional
Reading</h2>
</div>
<p>The indexed_set library under development by Joaqu&iacute;n
M&ordf; L&oacute;pez Mu&ntilde;oz. Google for &quot;indexed_set&quot; or see
the recent discussion at <a href=
"http://lists.boost.org/MailArchives/boost/msg54772.php" target=
"_top">http://lists.boost.org/MailArchives/boost/msg54772.php</a></p>
<p>A simple implementation of the <tt class="classname">map3</tt>
template for demonstration purposes can be found at <a href=
"http://home.clara.net/raoulgough/map/" target=
"_top">http://home.clara.net/raoulgough/map/</a></p>
</div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
