    <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  :: The Tale of a Struggling Template Programmer</title>
        <link>https://members.accu.org/index.php/journals/228</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>


        <h2>Journal Articles</h2>


<div class="xar-mod-head"><span class="xar-mod-title">Overload Journal #61 - Jun 2004 + Programming Topics</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/journals/">All</a>

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

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

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c151/">61</a>
                    (10)
<br />

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

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

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

                                            <a href="https://members.accu.org/index.php/journals/c151-65/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c151+65/">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;The Tale of a Struggling Template Programmer</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 01 June 2004 16:51:14 +01:00 or Tue, 01 June 2004 16:51:14 +01:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<div class="blockquote">
<blockquote class="blockquote">
<p>By relieving the brain of all unnecessary work, a good notation
sets it free to concentrate on more advanced problems, and in
effect increases the mental power of the race. (Alfred N.
Whitehead)</p>
</blockquote>
</div>
<p>I'm not exactly a beginner in C++ templates. Hey, I've even got
&quot;the book&quot; on it [<a href="#Vandevoorde-">Vandevoorde-</a>]! But,
admittedly, I'm not a guru - if I were, I wouldn't need the book.
So I was fairly confident that I could easily come up with a little
tool I have wanted to write for a while now. But it wasn't as easy
as I thought. For your amusement I'm going to show you what I set
out to do and what roadblocks I bumped into.</p>
<p>First, let me describe what I wanted to do. I have repeatedly
come across the need to do table lookups in constant tables of
key/value pairs. I program for embedded systems, so I am keen on
keeping the table itself in nonvolatile memory (ROM, Flash, or
whatever). I want to use binary search instead of linear search for
efficiency. This requires the table to be stored in sorted order.
Sorted according to the key alone, that is. Here's an example of
such a table (binary search is not really beneficial with such a
small table, but this is only a toy example):</p>
<pre class="programlisting">
const struct { int key; const char *value; }
table[] = {
  { 0, &quot;Ok&quot; },
  { 6, &quot;Minor glitch in self-destruction module&quot; },
  { 13, &quot;Error logging printer out of paper&quot; },
  { 101, &quot;Emergency cooling system inoperable&quot; },
  { 2349, &quot;Dangerous substances released&quot; },
  { 32767, &quot;Game over, you lost&quot; }
};
</pre>
<p>The first problem is to ensure the table is sorted. This is a
compile-time task, so in theory it could be a job for template (or
preprocessor) metaprogramming. If you're good at that, I've got
some homework for you. It's too difficult for me. I just resolved
to tell the programmer to make sure the table is sorted.</p>
<p>The second problem is simpler: Provide a lookup function that,
given a key, returns the associated value, or a default value if
the key could not be found in the table. Naturally, I wanted to
implement this as a function template that adapts to the actual key
and value types. As I want the tables to be put in nonvolatile
memory, they will in practice be of POD type (C-style arrays of
Cstyle structs). This is a much easier problem to solve, wouldn't
you agree? So pour yourself a glass of your favorite beverage,
install yourself in your armchair and chuckle while watching me
making a fool of myself.</p>
<p>The STL contains binary search algorithms, so it is sensible to
use them instead of inventing my own. The first attempt at my
function template uses <tt class="classname">std::equal_range</tt>
and goes like this:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val, unsigned n&gt;
const Val &amp;lookup(const std::pair&lt;Key,Val&gt;(&amp;tbl)[n],
                  const Key &amp;key, const Val &amp;def) {
  typedef const std::pair&lt;Key,Val&gt; Entry;
  Entry entry(key, Val());
  std::pair&lt;Entry*,Entry*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;second;
  return def;
}
</pre>
<p>You probably know or guessed that <tt class=
"classname">std::equal_range</tt> returns the range of entries
which compare equal to the value to be searched. If there are no
duplicates in the collection, this range will encompass either zero
or one element. Also note the declaration of the function parameter
<i class="parameter"><tt>tbl</tt></i>, which looks a bit weird at
first glance. This declaration specifies that <i class=
"parameter"><tt>tbl</tt></i> is a reference to an array whose
elements are of type <tt class="classname">const
std::pair&lt;Key,Val&gt;</tt> and whose size is <i class=
"parameter"><tt>n</tt></i> elements. Since <i class=
"parameter"><tt>Key</tt></i>, <i class="parameter"><tt>Val</tt></i>
and <i class="parameter"><tt>n</tt></i> are template parameters the
compiler deduces all this information at compile time. This version
of lookup hence requires the table to be an array of <tt class=
"constant">std::pair</tt> objects. The example table above thus has
to be changed to use <tt class="classname">std::pair&lt;int,const
char*&gt;</tt> instead of the anonymous struct. You use it like
this:</p>
<pre class="programlisting">
std::cout &lt;&lt; lookup(table,6,&quot;???&quot;) &lt;&lt; std::endl;
</pre>
<p>But alas, it doesn't work. As <tt class=
"classname">std::pair</tt> has constructors, it is not an
aggregate, and thus can not be initialized with the curly braces
notation. Try it: Your compiler will complain. For the same reason
it will most probably not be put into read-only storage. Clearly,
<tt class="classname">std::pair</tt> needs to be replaced by
something that allows aggregate initialization:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val&gt;
struct Pair {
  Key key;
  Val val;
};

template&lt;typename Key, typename Val, unsigned n&gt;
const Val &amp;lookup(const Pair&lt;Key,Val&gt;(&amp;tbl)[n],
                  const Key &amp;key, const Val &amp;def) {
  typedef const Pair&lt;Key,Val&gt; Entry;
  Entry entry = { key, Val() };
  std::pair&lt;Entry*,Entry*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>That didn't work either. Here's what Visual C++ 7.1 had to
say:</p>
<pre class="screen">
main.cpp(33) : error C2782: 'const Val
&amp;lookup(const Pair&lt;Key,Val&gt; (&amp;)[n],const Key
&amp;,const Val &amp;)' : template parameter 'Val' is
ambiguous
main.cpp(11) : see declaration of 'lookup'
could be 'const char [4]'
or 'const char *'
</pre>
<p>Ok, fair enough, I thought, the compiler might have a point
here. It can't figure out the proper type for <i class=
"parameter"><tt>Val</tt></i>, because it occurs twice in lookup's
signature (once as part of the <tt class="classname">Pair</tt>,
once as the type of the <i class="parameter"><tt>def</tt></i>
argument). What can we do about this? Well, I decided to try a
separate template parameter for the array element type, like
this:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val,
         typename Elem, unsigned n&gt;
const Val &amp;lookup(Elem(&amp;tbl)[n],
                  const Key &amp;key, const Val &amp;def) {
  Elem entry = { key, Val() };
  std::pair&lt;Elem*,Elem*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>I imagined that it would be easier for the compiler to figure
out the various type promotions/decays when doing the
initialization of the variable entry inside the function template.
This stuff would then not get in the way when it tried to deduce
the template parameters. The compiler still had something to
complain about, however:</p>
<pre class="screen">
main.cpp(13) : error C2440: 'type cast' : cannot
convert from 'int' to 'const char [4]'
  There are no conversions to array types,
although there are conversions to references or
pointers to arrays
  main.cpp(32) : see reference to function
template instantiation 'Val (&amp;lookup&lt;int,const
char[4],const Pair&lt;Key,const char *&gt;,7&gt;(Elem
(&amp;)[7],const Key &amp;,Val (&amp;)))' being compiled
  with
  [
    Val=const char [4],
    Key=int,
    Elem=const Pair&lt;int,const char *&gt;
  ]
main.cpp(16) : error C2440: 'return' : cannot
convert from 'const char *const ' to 'const char
(&amp;)[4]'
  Reason: cannot convert from 'const char *const '
to 'const char [4]'
  There are no conversions to array types,
although there are conversions to references or
pointers to arrays
</pre>
<p>The first error looked like complete idiocy to me. Why would the
compiler want to convert an <span class="type">int</span> to a
<span class="type">const char [4]</span> anyway? It had deduced the
template arguments correctly, hadn't it? Compiler confusion!</p>
<p>Let's look at the second error then, as it actually made some
sense to me. I'm using the <i class="parameter"><tt>Val</tt></i>
template parameter for the return type as well as the default
value, so it is no surprise that the compiler thinks it should be
an array when I'm providing an array in the call to lookup. That
can be fixed by forcing the pointer decay in the call to lookup,
like this:</p>
<pre class="programlisting">
std::cout &lt;&lt; lookup(table,6,(const char*)&quot;???&quot;)
          &lt;&lt; std::endl;
</pre>
<p>Disgusting, isn't it? It could be done with a more &quot;politically
correct&quot; type of cast, of course, but it is actually a nuisance to
need one in the first place. Let's see what we can do about
this:</p>
<pre class="programlisting">
template&lt;typename EKey, typename EVal,
         unsigned n, typename Key, typename Val&gt;
const EVal &amp;lookup(const Pair&lt;EKey,EVal&gt;(&amp;tbl)[n],
                   const Key &amp;key, const Val &amp;def) {
  typedef const Pair&lt;EKey,EVal&gt; Elem;
  Elem entry = { key, Val() };
  std::pair&lt;Elem*,Elem*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>Note that I reordered the template parameters to match the order
of occurrence in the function argument list. I thought that was a
good idea as the number of template parameters is growing. My
stupid compiler still doesn't get it:</p>
<pre class="screen">
main.cpp(14) : error C2440: 'type cast' : cannot
convert from 'int' to 'const char [4]'
  There are no conversions to array types,
although there are conversions to references or
pointers to arrays
main.cpp(33) : see reference to function template
instantiation 'const EVal &amp;lookup&lt;int,const
char*,7,int,const char[4]&gt;(const Pair&lt;Key,Val&gt;
(&amp;)[7],const Key &amp;,const char (&amp;)) ' being compiled
  with
  [
    EVal=const char *,
    Key=int,
    Val=const char *
  ]
main.cpp(18) : warning C4172: returning address of
local variable or temporary
</pre>
<p>I still can't figure out why the compiler wants to convert an
<span class="type">int</span> to a <span class="type">const char
[4]</span>, but the warning is sensible: <i class=
"parameter"><tt>Val</tt></i> and <i class=
"parameter"><tt>EVal</tt></i> aren't necessarily the same, so the
compiler is probably compelled to introduce a temporary in the last
return statement. This temporary of course goes away too soon. Ok,
that's easy to fix:</p>
<pre class="programlisting">
template&lt;typename EKey, typename EVal,
         unsigned n, typename Key, typename Val&gt;
EVal lookup(const Pair&lt;EKey,EVal&gt;(&amp;tbl)[n],
            const Key &amp;key, const Val &amp;def) {
  typedef const Pair&lt;EKey,EVal&gt; Elem;
  Elem entry = { key, Val() };
  std::pair&lt;Elem*,Elem*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>When <i class="parameter"><tt>Val</tt></i> is a <span class=
"type">const char*</span> the return by value is no more expensive
that the return by reference I used before. Alas, the value type
could well be something more complicated (a struct full of stuff),
so I'm not very happy to have a copy made. But if it must be it
shall be...</p>
<p>The weird error remains, however. So how about asking a
different compiler? Here's what GCC 3.3 says:</p>
<pre class="screen">
main.cpp: In function 'EVal lookup(const Pair&lt;EKey,
EVal&gt; (&amp;)[n], const Key&amp;, const Val&amp;) [with EKey =
int, EVal = const char*, unsigned int n = 7, Key =
int, Val = char[4]]':
main.cpp:33: instantiated from here
main.cpp:14: error: ISO C++ forbids casting to an
array type 'char[4]'
</pre>
<p>A number of further errors follow, but they're related to a
different problem to which I'm going to turn later. Let's first try
to find out what the error above means. Line 14 is where entry gets
initialized. So what's wrong with this? When two compilers more or
less agree, they might actually be right.</p>
<p>Both compilers seem to believe that I want a conversion from
<i class="parameter"><tt>EVal</tt></i> to <i class=
"parameter"><tt>Val</tt></i> (give or take a <tt class=
"literal">const</tt>). I would have thought it ought to be the
other way round. I construct a temporary of type <i class=
"parameter"><tt>Val</tt></i> and expect the compiler to convert it
to an <i class="parameter"><tt>EVal</tt></i> in order to initialize
the second field of the variable entry. In my particular case
<i class="parameter"><tt>Val</tt></i> is an array and <i class=
"parameter"><tt>EVal</tt></i> is a pointer, so the conversion
should simply be a decay. But why convert anyway? I've got an idea:
Let's construct an <i class="parameter"><tt>EVal</tt></i>
directly:</p>
<pre class="programlisting">
template&lt;typename EKey, typename EVal,
         unsigned n, typename Key, typename Val&gt;
EVal lookup(const Pair&lt;EKey,EVal&gt;(&amp;tbl)[n],
            const Key &amp;key, const Val &amp;def) {
  typedef const Pair&lt;EKey,EVal&gt; Elem;
  Elem entry = { key, EVal() };
  std::pair&lt;Elem*,Elem*&gt; range
         = std::equal_range(tbl, tbl+n, entry);
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>That sorts it out. But it feels as if I had merely dodged the
issue. I still don't know why the original attempt failed. If you
know, tell me.</p>
<p>That brings us to the next errors I mentioned above. GCC emits a
lot of error messages which are too numerous to print here, but
most of them contain the text <tt class="computeroutput">&quot;no match
for operator&lt;&quot;</tt>, which is actually quite right since I
obviously forgot to define how to compare a <tt class=
"classname">Pair</tt> to another. So I guess I have two options
here. I could either provide <tt class=
"methodname">operator&lt;</tt> for a <tt class=
"classname">Pair</tt> or I could provide a custom predicate to
<tt class="classname">std::equal_range</tt> to do the comparison. I
only want to compare the keys, so I feel that the first option
amounts to cheating. If someone else wanted to compare two
<tt class="classname">Pair</tt>s and did not know about my
ruminations here she would probably expect <tt class=
"methodname">operator&lt;</tt> to take both fields of the
<tt class="classname">Pair</tt> into account.</p>
<p>So I think I should rather provide a special predicate with a
sensible name like <tt class="function">LessKey</tt> that makes it
clear that only the key is being compared. Here we go:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val&gt;
struct LessKey : std::binary_function&lt;
                       const Pair&lt;Key,Val&gt;&amp;,
                       const Pair&lt;Key,Val&gt;&amp;,bool&gt; {
  result_type operator()(first_argument_type a,
                      second_argument_type b) const
  { return a.key &lt; b.key; }
};
</pre>
<p>Look Ma! I even made it adaptable by deriving from <tt class=
"classname">std::binary_function</tt>! I earned extra brownie
points for that, didn't I? My lookup function template now looks
like this:</p>
<pre class="programlisting">
template&lt;typename EKey, typename EVal,
         unsigned n, typename Key, typename Val&gt;
EVal lookup(const Pair&lt;EKey,EVal&gt;(&amp;tbl)[n],
            const Key &amp;key, const Val &amp;def) {
  typedef LessKey&lt;EKey,EVal&gt; Pred;
  typedef const Pair&lt;EKey,EVal&gt; Elem;
  Elem entry = { key, EVal() };
  std::pair&lt;Elem*,Elem*&gt; range
         = std::equal_range(tbl, tbl+n, entry, Pred());
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}
</pre>
<p>Needless to say, GCC still isn't happy. It emits a series of
warnings regarding the implicit usage of <tt class=
"literal">typename</tt>. Here's just one of them:</p>
<pre class="screen">
main.cpp:14: Warning: 'LessKey&lt;Key,
Val&gt;::result_type' is implicitly a typename
main.cpp:14: Warning: implicit typename is
deprecated, please see the documentation for
details
</pre>
<p>The same happens for <i class=
"parameter"><tt>first_argument_type</tt></i> and <i class=
"parameter"><tt>second_argument_type</tt></i>. I could ignore those
as they're only warnings, but I want to get it right. Furthermore I
think I know what's amiss: I need to use the keyword typename to
make clear that they are types. Next try:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val&gt;
struct LessKey : std::binary_function&lt;
                       const Pair&lt;Key,Val&gt;&amp;,
                       const Pair&lt;Key,Val&gt;&amp;,bool&gt; {
  typename result_type operator()(
        typename first_argument_type a,
        typename second_argument_type b) const
  { return a.key &lt; b.key; }
};
</pre>
<p>Now, GCC defecates an even bigger heap of error messages onto me
('scuse my French!). I don't want to spare you the experience:</p>
<pre class="screen">
main.cpp:13: error: Fehler beim Parsen before
'operator'
/usr/include/c++/3.3/bits/stl_algo.h: In function
'std::pair&lt;_ForwardIter, _ForwardIter&gt;
std::equal_range(_ForwardIter, _ForwardIter, const
_Tp&amp;, _Compare) [with _ForwardIter = const
Pair&lt;int, const char*&gt;*, _Tp = Pair&lt;int, const
char*&gt;, _Compare = LessKey&lt;int, const char*&gt;]':
main.cpp:22: instantiated from 'EVal lookup(const
Pair&lt;Key, Val&gt; (&amp;)[n], const Key&amp;, const Val&amp;)
[with EKey = int, EVal = const char*, unsigned int
n = 7, Key = int, Val = char[4]]'
main.cpp:40: instantiated from here
/usr/include/c++/3.3/bits/stl_algo.h:3026: error:
no match for call to '(LessKey&lt;int, const char*&gt;)
(const Pair&lt;int, const char*&gt;&amp;, const Pair&lt;int,
const char*&gt;&amp;)'
/usr/include/c++/3.3/bits/stl_algo.h:3031: error:
no match for call to '(LessKey&lt;int, const char*&gt;)
(const Pair&lt;int, const char*&gt;&amp;, const Pair&lt;int,
const char*&gt;&amp;)'
/usr/include/c++/3.3/bits/stl_algo.h: In function
'_ForwardIter std::lower_bound(_ForwardIter,
_ForwardIter, const _Tp&amp;, _Compare) [with
_ForwardIter = const Pair&lt;int, const char*&gt;*, _Tp =
Pair&lt;int, const char*&gt;, _Compare = LessKey&lt;int,
const char*&gt;]':
/usr/include/c++/3.3/bits/stl_algo.h:3034:
instantiated from 'std::pair&lt;_ForwardIter,
_ForwardIter&gt; std::equal_range(_ForwardIter,
_ForwardIter, const _Tp&amp;, _Compare) [with
_ForwardIter = const Pair&lt;int, const char*&gt;*, _Tp =
Pair&lt;int, const char*&gt;, _Compare = LessKey&lt;int,
const char*&gt;]'
main.cpp:22: instantiated from 'EVal lookup(const
Pair&lt;Key, Val&gt; (&amp;)[n], const Key&amp;, const Val&amp;)
[with EKey = int, EVal = const char*, unsigned int
n = 7, Key = int, Val = char[4]]'
main.cpp:40: instantiated from here
/usr/include/c++/3.3/bits/stl_algo.h:2838: error:
no match for call to '(LessKey&lt;int, const char*&gt;)
(const Pair&lt;int, const char*&gt;&amp;, const Pair&lt;int,
const char*&gt;&amp;)'
/usr/include/c++/3.3/bits/stl_algo.h: In function
'_ForwardIter std::upper_bound(_ForwardIter,
_ForwardIter, const _Tp&amp;, _Compare) [with
_ForwardIter = const Pair&lt;int, const char*&gt;*, _Tp =
Pair&lt;int, const char*&gt;, _Compare = LessKey&lt;int,
const char*&gt;]':
/usr/include/c++/3.3/bits/stl_algo.h:3036:
instantiated from `std::pair&lt;_ForwardIter,
_ForwardIter&gt; std::equal_range(_ForwardIter,
_ForwardIter, const _Tp&amp;, _Compare) [with
_ForwardIter = const Pair&lt;int, const char*&gt;*, _Tp =
Pair&lt;int, const char*&gt;, _Compare = LessKey&lt;int,
const char*&gt;]'
main.cpp:22: instantiated from 'EVal lookup(const
Pair&lt;Key, Val&gt; (&amp;)[n], const Key&amp;, const Val&amp;)
[with EKey = int, EVal = const char*, unsigned int
n = 7, Key = int, Val = char[4]]'
main.cpp:40: instantiated from here
/usr/include/c++/3.3/bits/stl_algo.h:2923: error:
no match for call to '(LessKey&lt;int, const char*&gt;)
(const Pair&lt;int, const char*&gt;&amp;, const Pair&lt;int,
const char*&gt;&amp;)'
</pre>
<p>I hope the occasional German word in there doesn't irritate you.
Having part of the output of tools translated to German with the
remainder in English leads to interesting effects. That's a story
for another day.</p>
<p>Are you actually able to spot what's wrong from the gobbledygook
above? I wasn't. Give me a hint if you are. All it tells me is that
GCC ran into a parsing error in a system library because of the
code I wrote (!). Is this a GCC bug? Visual C++ 7.1 is happy with
it, no matter whether the <tt class="literal">typename</tt>
keywords are there or not. So do I need them or not? How do I write
this correctly?</p>
<p>Time to consult &quot;the book&quot;[<a href=
"#Vandevoorde-">Vandevoorde-</a>]! On page 131 we can find the
following description:</p>
<div class="blockquote">
<blockquote class="blockquote">
<p>&quot;The typename prefix to a name is required when the name</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>Appears in a template</p>
</li>
<li>
<p>Is qualified</p>
</li>
<li>
<p>Is not used as in a list of base class specifications or in a
list of member initializers introducing a constructor
definition</p>
</li>
<li>
<p>Is dependent on a template parameter</p>
</li>
</ol>
</div>
<p>Furthermore, the typename prefix is not allowed unless at least
the first three previous conditions hold.&quot;</p>
</blockquote>
</div>
<p>Ok, let's see whether I can make any sense of this: Rules 1 and
3 are obviously met. Rule 4 seems to be met indirectly, since
<span class="type">result_type</span> is defined by the base class
<tt class="classname">std::binary_function</tt>, which in turn is a
class template that depends on both template parameters <i class=
"parameter"><tt>Key</tt></i> and <i class=
"parameter"><tt>Var</tt></i>. However, rule 2 seems to be violated,
as I can not see any qualification. So I conclude that typename
shouldn't even be allowed where I put them. So GCC is technically
right although it should have generated better error messages.
Visual C++ accepted wrong code without complaint. But what is wrong
with the original version without typename, why is GCC issuing a
warning? Rule 2 pretty much excludes that a <tt class=
"literal">typename</tt> is missing elsewhere.</p>
<p>I solved the problem by not using <span class=
"type">return_type</span> and its siblings from <tt class=
"classname">std::binary_function</tt>. The following is accepted by
both GCC and Visual C++:</p>
<pre class="programlisting">
template&lt;typename Key, typename Val&gt;
struct LessKey : std::binary_function&lt;
                     const Pair&lt;Key,Val&gt;&amp;,
                     const Pair&lt;Key,Val&gt;&amp;,bool&gt; {
  bool operator()(const Pair&lt;Key,Val&gt; &amp;a,
                  const Pair&lt;Key,Val&gt; &amp;b) const
  { return a.key &lt; b.key; }
};
</pre>
<p>Again, I had chickened out instead of solving the problem.
Swallowing my pride, I went on to the next challenge:</p>
<pre class="programlisting">
const char *result = lookup(table,6,0);
</pre>
<p>I guess you see what I want to achieve?!? I want lookup to
return a null pointer if the key wasn't found in the table. For a
table that contains strings as values this is sensible, wouldn't
you agree?</p>
<p>It doesn't compile. You already guessed why: The third argument
to the lookup function gets interpreted as an integer as opposed to
a null pointer, so the compiler comes up with the wrong choices for
the template parameters and as a consequence the statement
&quot;<tt class="literal">return def;</tt>&quot; fails to compile. I would
have to write something like this:</p>
<pre class="programlisting">
const char *result = lookup(table,6,(char*)0);
</pre>
<p>But that's ugly; can you really expect that from an innocent
user of my templates? What about this:</p>
<pre class="programlisting">
const char *result = lookup(table,6,NULL);
</pre>
<p>Nope, the compiler still interprets the NULL as an integer
constant. Back to square 1. GCC's error message is actually quite
interesting:</p>
<pre class="screen">
main.cpp: In function 'int main()':
main.cpp:40: Warnung: passing NULL used for nonpointer
converting 3 of 'EVal lookup(const
Pair&lt;Key, Val&gt; (&amp;)[n], const Key&amp;, const Val&amp;)
[with EKey = int, EVal = const char*, unsigned int
n = 7, Key = int, Val = int]'
main.cpp: In function 'EVal lookup(const Pair&lt;Key,
Val&gt; (&amp;)[n], const Key&amp;, const Val&amp;) [with EKey =
int, EVal = const char*, unsigned int n = 7, Key =
int, Val = int]':
main.cpp:40: instantiated from here
main.cpp:25: error: invalid conversion from 'const
int' to 'const char*'
</pre>
<p>The compiler does indeed notice that <tt class=
"literal">NULL</tt> is being used as a non-pointer, but it still
pigheadedly decides to instantiate the template with <tt class=
"literal">Val = int</tt>.</p>
<p>Despair sets in, creeping slowly from the back of my head
towards the front. Is there any hope to get this right? Am I trying
to do something frivolous? Illegal? Immoral? Fattening? Time to
step back and take a deep breath. What can we learn from this?</p>
<p>It doesn't take much to get into serious trouble with templates.
This doesn't mean that templates themselves are to blame. It is
rather the interaction between templates and other C++ &quot;features&quot;
that cause problems. It is similar to combining drugs: Each one is
harmless when taken alone, but taken together they might kill
you.</p>
<p>Over the last years we have seen an increasing number of tricks
and workarounds attempting to control and contain the unwanted
effects of these interactions. Library designers are forced to know
and use them to prevent unpleasant surprises for the mere mortal
library user. Here's a short list of idiosyncrasies that I just
came up with ad-hoc. You're invited to add your favorites to it.
Maybe we could create a &quot;C++ derision web page&quot; from it. I hope you
don't take this seriously enough to be offended.</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>Angle brackets being mistaken as shift operators in nested
template declarations</p>
</li>
<li>
<p>The need to put in additional <tt class="literal">typename</tt>
keywords in obscure circumstances</p>
</li>
<li>
<p>The need to put in additional template keywords in even more
obscure circumstances</p>
</li>
<li>
<p>The need to use <tt class="literal">this-&gt;</tt> explicitly to
control name lookup in templates in another set of obscure
circumstances</p>
</li>
<li>
<p>The often unwanted effects of automatic type
conversions/promotion/decay on template argument deduction and
overload resolution.</p>
</li>
<li>
<p>The fact that <span class="type">bool</span> converts to
<span class="type">int</span> automatically. This has the effect
that returning a member function pointer is sometimes superior to
returning a <span class="type">bool</span> because it doesn't
convert as easily. (Savour this: Member function pointers are
better booleans than <span class="type">bool</span>!)</p>
</li>
<li>
<p>The fact that the literal <tt class="literal">0</tt> converts to
the null pointer.</p>
</li>
<li>
<p>The C/C++ declaration syntax (need I say more?)</p>
</li>
<li>
<p>Argument-Dependent Lookup</p>
</li>
</ul>
</div>
<p>To me it seems the more experience I've gained programming in
C++ the more I realize how inadequate my skill still is. I have
been programming in C++ for a considerable time now, I have read
numerous books on the subject, and still I don't seem to have it
under control. This bothers me. How can an average programmer be
expected to cope with this? Imagine for a moment yourself giving a
lecture to a classroom full of the type of programmers you meet in
your working life. Your topic is the sort of stuff I came across in
my example above. Just imagine the puzzled faces.</p>
<p>I don't know what to do about this. If the other languages
weren't even worse in one way or another I would probably switch.
But so far I haven't seen anything I like 100%. I had a look at
Haskell, and I generally liked what I saw, particularly regarding
generic programming, but I couldn't see how to apply this to
embedded programming, where you deal extensively with low-level
stuff that is rather close to the hardware level. Here I would like
to be able to predict what kind of code is being generated. With
Haskell I feel I have no control over this. Maybe that's because
I'm not experienced enough with it.</p>
<p>My dream language would take Haskell's elegant type inference
machinery and built-in list/tuple/array manipulation and combine it
with a more &quot;conventional&quot; syntax. It must support object-oriented
and imperative programming styles, because I can't see how I could
do without them in embedded programming.</p>
<p>My feeling is that languages that have genericity tagged on as
an afterthought are not really satisfactory. Backwards
compatibility is likely to prevent cleaning up the rough edges. The
result is the sort of thing we have now with C++: The language is
very complicated and has lots of obscure and surprising special
cases. I am asking myself if it would not be possible to deprecate
troublesome features in a language more aggressively. I know of
course that C++ has become popular precisely because of its
backward compatibility and that right now the standard committees
for C and C++ are cooperating closely to ensure that this remains
so.</p>
<p>Back in now ancient times the ANSI C standard introduced
function prototypes, offering a better alternative to K&amp;R style
function declarations. I haven't seen any K&amp;R style code for a
while now. It still exists, but it is now customary to require a
compiler switch to make the compiler accept the old form. Can't
something similar be done with C++? Something like a C++ generation
2 that is not backwards compatible with the current generation, but
is linkcompatible with it. And the compiler would continue to
accept the old version while it is gradually being phased out.</p>
<p>To wind up, let's see where we are with my little problem.
Here's the complete code as it stands now:</p>
<pre class="programlisting">
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;functional&gt;
template&lt;typename Key, typename Val&gt;
struct Pair { Key key; Val val; };
template&lt;typename Key, typename Val&gt;
struct LessKey : std::binary_function&lt;
    const Pair&lt;Key,Val&gt;&amp;, const Pair&lt;Key,Val&gt;&amp;,bool&gt; {
  bool operator()(const Pair&lt;Key,Val&gt; &amp;a,
                  const Pair&lt;Key,Val&gt; &amp;b) const
  { return a.key &lt; b.key; }
};

template&lt;typename EKey, typename EVal,
         unsigned n, typename Key, typename Val&gt;
EVal lookup(const Pair&lt;EKey,EVal&gt;(&amp;tbl)[n],
            const Key &amp;key, const Val &amp;def) {
  typedef LessKey&lt;EKey,EVal&gt; Pred;
  typedef const Pair&lt;EKey,EVal&gt; Elem;
  Elem entry = { key, EVal() };
  std::pair&lt;Elem*,Elem*&gt; range
      = std::equal_range(tbl, tbl+n, entry, Pred());
  if(range.first != range.second)
    return range.first-&gt;val;
  return def;
}

const Pair&lt;int, const char*&gt; table[] = {
  { 0, &quot;Ok&quot; },
  { 6, &quot;Minor glitch in self-destruction module&quot; },
  { 13, &quot;Error logging printer out of paper&quot; },
  { 101, &quot;Emergency cooling system inoperable&quot; },
  { 2349, &quot;Dangerous substances released&quot; },
  { 32767, &quot;Game over, you lost&quot; }
};

int main() {
  const char *result = lookup(table,6,(char*)0);
  std::cout &lt;&lt; (result ? result : &quot;not found&quot;)
            &lt;&lt; std::endl; 
}
</pre>
<p>It has the following problems:</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>It requires the ugly cast for passing the null pointer as the
third argument to <tt class="function">lookup</tt></p>
</li>
<li>
<p><tt class="function">lookup</tt> returns the result by value,
which can be inefficient</p>
</li>
<li>
<p>It is still unclear why I couldn't use the <tt class=
"literal">typedef</tt>s from <tt class=
"classname">std::binary_function</tt> in the <tt class=
"function">LessKey</tt> predicate (only with gcc)</p>
</li>
<li>
<p>Neither do I know why the compiler wanted to convert the wrong
way between <i class="parameter"><tt>Val</tt></i> and <i class=
"parameter"><tt>EVal</tt></i></p>
</li>
</ul>
</div>
<p>So if you want to have a go, you're invited to contribute your
solutions. I'd like to know how this is done right!</p>
<p><span class="editorial">Developers are people too, and hate to
admit that they are confused or that their understanding is
incomplete. We should be grateful therefore that Stefan was willing
to write this article which illustrates the potential C++ has for
causing these symptoms even in experienced developers. It is said
that an admission of ignorance is the first step to wisdom and
further steps were taken when one of Overload's Readers became
interested in solving the problem presented above. If you wish to
tackle this exercise yourself then you may want to postpone reading
the results of their collaboration (which, in the traditional
manner, appears towards the end of this magazine). (AG)</span></p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2>Conventional
Programming Languages: Fat and Flabby</h2>
</div>
<div class="blockquote">
<blockquote class="blockquote">
<p>For twenty years programming languages have been steadily
progressing toward their present condition of obesity; ... it is
now the province of those who prefer to work with thick compendia
of details rather than wrestle with new ideas. (John Backus,
1977)</p>
</blockquote>
</div>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e451" id=
"d0e451"></a>Acknowledgements</h2>
</div>
<p>Thanks to the reviewers Phil Bass, Thaddaeus Frogley and Alan
Griffiths for their comments.</p>
</div>
<div class="bibliography">
<div class="titlepage">
<h2>
</div>
<div class="bibliomixed"><a name="Vandevoorde-" id=
"Vandevoorde-"></a>
<p class="bibliomixed">[Vandevoorde-] D. Vandevoorde, N. M.
Josuttis, C++ Templates: The complete guide, Addison-Wesley,
2003</p>
</div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
