⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap06.htm

📁 This is the second part of that lab manual to teach you how to make real-time programme and how to d
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<font color=#009900>// Template-template argument must </font>
<font color=#009900>// be a class; cannot use typename:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> T, <font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font>&gt; <font color=#0000ff>class</font> C&gt;
<font color=#0000ff>void</font> print2(C&lt;T&gt;&amp; c) {
  copy(c.begin(), c.end(), 
    ostream_iterator&lt;T&gt;(cout, <font color=#004488>" "</font>));
  cout &lt;&lt; endl;
}

<font color=#0000ff>int</font> main() {
  vector&lt;string&gt; v(5, <font color=#004488>"Yow!"</font>);
  print1(v);
  print2(v);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><A NAME="_Toc519041989"></A><BR></P></DIV>
<A NAME="Heading166"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Member function templates</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It&#8217;s also possible to make
<B>apply(&#160;)</B> a <I>member function
template<A NAME="Index476"></A><A NAME="Index477"></A><A NAME="Index478"></A></I>
of the class. That is, a separate template definition from the class&#8217;
template, and yet a member of the class. This may produce a cleaner
syntax:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>dogs.apply(&amp;Gromit::sit);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is analogous to the act (in Chapter
XX) of bringing ordinary functions inside a
class.</FONT><A NAME="fnB18" HREF="#fn18">[18]</A><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The definition of the
<B>apply(&#160;)</B> functions turn out to be cleaner, as well, because they are
members of the container. To accomplish this, a new container is inherited from
one of the existing STL sequence containers and the member function templates
are added to the new type. However, for maximum flexibility we&#8217;d like to
be able to use any of the STL sequence containers, and for this to work a
<I>template-template</I> must be used, to tell the compiler that a template
argument is actually a template, itself, and can thus take a type argument and
be instantiated. Here is what it looks like after bringing the
<B>apply(&#160;)</B> functions into the new type as member
functions:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:applyMember.h</font>
<font color=#009900>// applySequence.h modified to use </font>
<font color=#009900>// member function templates</font>

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font>&gt; <font color=#0000ff>class</font> Seq&gt;
<font color=#0000ff>class</font> SequenceWithApply : <font color=#0000ff>public</font> Seq&lt;T*&gt; {
<font color=#0000ff>public</font>:
  <font color=#009900>// 0 arguments, any type of return value:</font>
  <font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> R&gt;
  <font color=#0000ff>void</font> apply(R (T::*f)()) {
    iterator it = begin();
    <font color=#0000ff>while</font>(it != end()) {
      ((*it)-&gt;*f)();
      it++;
    }
  }
  <font color=#009900>// 1 argument, any type of return value:</font>
  <font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> R, <font color=#0000ff>class</font> A&gt;
  <font color=#0000ff>void</font> apply(R(T::*f)(A), A a) {
    iterator it = begin();
    <font color=#0000ff>while</font>(it != end()) {
      ((*it)-&gt;*f)(a);
      it++;
    }
  }
  <font color=#009900>// 2 arguments, any type of return value:</font>
  <font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> R, <font color=#0000ff>class</font> A1, <font color=#0000ff>class</font> A2&gt;
  <font color=#0000ff>void</font> apply(R(T::*f)(A1, A2), 
    A1 a1, A2 a2) {
    iterator it = begin();
    <font color=#0000ff>while</font>(it != end()) {
      ((*it)-&gt;*f)(a1, a2);
      it++;
    }
  }
}; <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because they are members, the
<B>apply(&#160;)</B> functions don&#8217;t need as many arguments, and the
<B>iterator</B> class doesn&#8217;t need to be qualified. Also,
<B>begin(&#160;)</B> and <B>end(&#160;)</B> are now member functions of the new
type and so look cleaner as well. However, the basic code is still the
same.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see how the function calls are
also simpler for the client programmer:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:applyGromit2.cpp</font>
<font color=#009900>// Test applyMember.h</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295}</font>
<font color=#009900>//{-g++3}</font>
<font color=#009900>//{-msc}</font>
#include <font color=#004488>"Gromit.h"</font>
#include <font color=#004488>"applyMember.h"</font>
#include &lt;vector&gt;
#include &lt;iostream&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  SequenceWithApply&lt;Gromit, vector&gt; dogs;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 5; i++)
    dogs.push_back(<font color=#0000ff>new</font> Gromit(i));
  dogs.apply(&amp;Gromit::speak, 1);
  dogs.apply(&amp;Gromit::eat, 2.0f);
  dogs.apply(&amp;Gromit::sleep, 'z', 3.0);
  dogs.apply(&amp;Gromit::sit);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Conceptually, it reads more sensibly to
say that you&#8217;re calling <B>apply(&#160;)</B> for the <B>dogs</B>
container.</FONT><A NAME="_Toc519041990"></A><BR></P></DIV>
<A NAME="Heading167"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Why virtual member template functions are
disallowed<A NAME="_Toc519041991"></A></H3></FONT>
<A NAME="Heading168"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Nested template
classes<A NAME="_Toc312374093"></A><A NAME="_Toc519041992"></A></H3></FONT>
<A NAME="Heading169"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Template specializations<A NAME="_Toc519041993"></A></H2></FONT>
<A NAME="Heading170"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Full specialization<A NAME="_Toc519041994"></A></H3></FONT>
<A NAME="Heading171"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Partial Specialization<A NAME="_Toc519041995"></A></H3></FONT>
<A NAME="Heading172"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
A practical example<BR><A NAME="Index479"></A><A NAME="Index480"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s nothing to prevent you from
using a class template in any way you&#8217;d use an ordinary class. For
example, you can easily inherit from a template, and you can create a new
template that instantiates and inherits from an existing template. If the
<B>vector </B>class does everything you want, but you&#8217;d also like it to
sort itself, you can easily reuse the code and add value to it:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Sorted.h</font>
<font color=#009900>// Template specialization</font>
#ifndef SORTED_H
#define SORTED_H
#include &lt;vector&gt;

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T&gt;
<font color=#0000ff>class</font> Sorted : <font color=#0000ff>public</font> std::vector&lt;T&gt; {
<font color=#0000ff>public</font>:
  <font color=#0000ff>void</font> sort();
};

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T&gt;
<font color=#0000ff>void</font> Sorted&lt;T&gt;::sort() { <font color=#009900>// A bubble sort</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = size(); i &gt; 0; i--)
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 1; j &lt; i; j++)
      <font color=#0000ff>if</font>(at(j-1) &gt; at(j)) {
        <font color=#009900>// Swap the two elements:</font>
        T t = at(j-1);
        at(j-1) = at(j);
        at(j) = t;
      }
}

<font color=#009900>// Partial specialization for pointers:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T&gt;
<font color=#0000ff>class</font> Sorted&lt;T*&gt; : <font color=#0000ff>public</font> std::vector&lt;T*&gt; {
<font color=#0000ff>public</font>:
  <font color=#0000ff>void</font> sort();
};

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T&gt;
<font color=#0000ff>void</font> Sorted&lt;T*&gt;::sort() {
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = size(); i &gt; 0; i--)
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 1; j &lt; i; j++)
      <font color=#0000ff>if</font>(*at(j-1) &gt; *at(j)) {
        <font color=#009900>// Swap the two elements:</font>
        T* t = at(j-1);
        at(j-1) = at(j);
        at(j) = t;
      }
}

<font color=#009900>// Full specialization for char*:</font>
<font color=#0000ff>template</font>&lt;&gt;
<font color=#0000ff>void</font> Sorted&lt;<font color=#0000ff>char</font>*&gt;::sort() {
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = size(); i &gt; 0; i--)
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 1; j &lt; i; j++)
      <font color=#0000ff>if</font>(strcmp(at(j-1), at(j)) &gt; 0) {
        <font color=#009900>// Swap the two elements:</font>
        <font color=#0000ff>char</font>* t = at(j-1);
        at(j-1) = at(j);
        at(j) = t;
      }
}
#endif <font color=#009900>// SORTED_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Sorted</B> template imposes a
restriction on all classes it is instantiated for: They must contain a
<B>&gt;</B> operator. In <B>SString</B> this is added explicitly, but in
<B>Integer</B> the automatic type conversion <B>operator int</B> provides a path
to the built-in <B>&gt;</B> operator. When a template
<A NAME="Index481"></A>provides more functionality for you, the trade-off is
usually that it puts more requirements on your class. Sometimes you&#8217;ll
have to inherit the contained class to add the required functionality. Notice
the value of using an overloaded operator here &#8211; the <B>Integer</B> class
can rely on its underlying implementation to provide the
functionality.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default <B>Sorted</B> template only
works with objects (including objects of built-in types). However, it
won&#8217;t sort pointers to objects so the partial specialization is necessary.
Even then, the code generated by the partial specialization won&#8217;t sort an
array of <B>char*</B>. To solve this, the full specialization compares the
<B>char*</B> elements using <B>strcmp(&#160;)</B> to produce the proper
behavior.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s a test for <B>Sorted.h</B>
that uses the unique random number generator introduced earlier in the
chapter:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Sorted.cpp</font>
<font color=#009900>// Testing template specialization</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295}</font>
<font color=#009900>//{-msc}</font>
#include <font color=#004488>"Sorted.h"</font>
#include <font color=#004488>"Urand.h"</font>
#include <font color=#004488>"..</font><font color=#004488>/arraySize.h"</font>
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>char</font>* words[] = {
  <font color=#004488>"is"</font>, <font color=#004488>"running"</font>, <font color=#004488>"big"</font>, <font color=#004488>"dog"</font>, <font color=#004488>"a"</font>,
};
<font color=#0000ff>char</font>* words2[] = {
  <font color=#004488>"this"</font>, <font color=#004488>"that"</font>, <font color=#004488>"theother"</font>,
};

<font color=#0000ff>int</font> main() {
  Sorted&lt;<font color=#0000ff>int</font>&gt; is;
  Urand&lt;47&gt; rand;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 15; i++)
    is.push_back(rand());
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> l = 0; l &lt; is.size(); l++)
    cout &lt;&lt; is[l] &lt;&lt; ' ';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -