📄 chap06.htm
字号:
cout << endl;
is.sort();
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> l = 0; l < is.size(); l++)
cout << is[l] << ' ';
cout << endl;
<font color=#009900>// Uses the template partial specialization:</font>
Sorted<string*> ss;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < asz(words); i++)
ss.push_back(<font color=#0000ff>new</font> string(words[i]));
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < ss.size(); i++)
cout << *ss[i] << ' ';
cout << endl;
ss.sort();
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < ss.size(); i++)
cout << *ss[i] << ' ';
cout << endl;
<font color=#009900>// Uses the full char* specialization:</font>
Sorted<<font color=#0000ff>char</font>*> scp;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < asz(words2); i++)
scp.push_back(words2[i]);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < scp.size(); i++)
cout << scp[i] << ' ';
cout << endl;
scp.sort();
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < scp.size(); i++)
cout << scp[i] << ' ';
cout << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Each of the template instantiations uses
a different version of the template. <B>Sorted<int></B> uses the
“ordinary,” non-specialized template. <B>Sorted<string*></B>
uses the partial specialization for pointers. Lastly, <B>Sorted<char*></B>
uses the full specialization for <B>char*</B>. Note that without this full
specialization, you could be fooled into thinking that things were working
correctly because the <B>words</B> array would still sort out to “a big
dog is running” since the partial specialization would end up comparing
the first character of each array. However, <B>words2</B> would not sort out
correctly, and for the desired behavior the full specialization is
necessary.</FONT><BR></P></DIV>
<A NAME="Heading173"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Pointer specialization</H4></FONT>
<A NAME="Heading174"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Partial ordering of function
templates<A NAME="_Toc312374085"></A><A NAME="_Toc519041996"></A></H4></FONT>
<A NAME="Heading175"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Design & efficiency<BR><A NAME="Index482"></A><A NAME="Index483"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Sorted</B>, every time you call
<B>add( )</B> the element is inserted and the array is resorted. Here, the
horribly inefficient and greatly deprecated (but easy to understand and code)
bubble sort <A NAME="Index484"></A><A NAME="Index485"></A>is used. This is
perfectly appropriate, because it’s part of the <B>private</B>
implementation. During program development, your priorities are
to</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Get the class interfaces
correct.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Create an
accurate implementation as rapidly as possible so you
can:</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Prove your
design.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Very often, you will
discover problems with the class interface only when you assemble your initial
“rough draft” of the working system. You may also discover the need
for “helper” classes like containers and iterators during system
assembly and during your first-pass implementation. Sometimes it’s very
difficult to discover these kinds of issues during analysis – your goal in
analysis should be to get a big-picture design that can be rapidly
implemented<A NAME="Index486"></A> and tested. Only after the design has been
proven should you spend the time to flesh it out completely and worry about
performance issues. If the design fails, or if performance is not a problem, the
bubble sort is good enough, and you haven’t wasted any time. (Of course,
the ideal solution is to use someone else’s sorted container; the Standard
C++ template library is the first place to
look.)</FONT><A NAME="_Toc312374086"></A><A NAME="_Toc519041997"></A><BR></P></DIV>
<A NAME="Heading176"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Preventing template bloat<BR><A NAME="Index487"></A><A NAME="Index488"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Each time you instantiate a template, the
code in the template is generated anew (except for <B>inline</B> functions). If
some of the functionality of a template does not depend on type, it can be put
in a common base class to prevent needless reproduction of that code. For
example, in Chapter XX in <B>InheritStack.cpp</B> inheritance was used to
specify the types that a <B>Stack</B> could accept and produce. Here’s the
templatized version of that code:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Nobloat.h</font>
<font color=#009900>// Templatized InheritStack.cpp</font>
#ifndef NOBLOAT_H
#define NOBLOAT_H
#include <font color=#004488>"..</font><font color=#004488>/C0B</font><font color=#004488>/Stack4.h"</font>
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T>
<font color=#0000ff>class</font> NBStack : <font color=#0000ff>public</font> Stack {
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> push(T* str) {
Stack::push(str);
}
T* peek() <font color=#0000ff>const</font> {
<font color=#0000ff>return</font> (T*)Stack::peek();
}
T* pop() {
<font color=#0000ff>return</font> (T*)Stack::pop();
}
~NBStack();
};
<font color=#009900>// Defaults to heap objects & ownership:</font>
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T>
NBStack<T>::~NBStack() {
T* top = pop();
<font color=#0000ff>while</font>(top) {
<font color=#0000ff>delete</font> top;
top = pop();
}
}
#endif <font color=#009900>// NOBLOAT_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As before, the inline functions generate
no code and are thus “free.” The functionality is provided by
creating the base-class code only once. However, the ownership problem has been
solved here by adding a destructor (which <I>is</I> type-dependent, and thus
must be created by the template). Here, it defaults to ownership. Notice that
when the base-class destructor is called, the stack will be empty so no
duplicate releases will occur.</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:NobloatTest.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test </font>
#include <font color=#004488>"Nobloat.h"</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include <fstream>
#include <iostream>
#include <string>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>int</font> main() {
ifstream in(<font color=#004488>"NobloatTest.cpp"</font>);
assure(in, <font color=#004488>"NobloatTest.cpp"</font>);
NBStack<string> textlines;
string line;
<font color=#009900>// Read file and store lines in the stack:</font>
<font color=#0000ff>while</font>(getline(in, line))
textlines.push(<font color=#0000ff>new</font> string(line));
<font color=#009900>// Pop the lines from the stack and print them:</font>
string* s;
<font color=#0000ff>while</font>((s = (string*)textlines.pop()) != 0) {
cout << *s << endl;
<font color=#0000ff>delete</font> s;
}
} <font color=#009900>///:~<A NAME="_Toc519041998"></A></font></PRE></FONT></BLOCKQUOTE><A NAME="Heading177"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Explicit instantiation<BR><A NAME="Index489"></A><A NAME="Index490"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">At times it is useful to explicitly
instantiate a template; that is, to tell the compiler to lay down the code for a
specific version of that template even though you’re not creating an
object at that point. To do this, you reuse the <B>template</B> keyword as
follows:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>template</font> <font color=#0000ff>class</font> Bobbin<thread>;
<font color=#0000ff>template</font> <font color=#0000ff>void</font> sort<<font color=#0000ff>char</font>>(<font color=#0000ff>char</font>*[]);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s a version of the
<B>Sorted.cpp</B> example that explicitly instantiates a template before using
it:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:ExplicitInstantiation.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295}</font>
<font color=#009900>//{-msc}</font>
#include <font color=#004488>"Urand.h"</font>
#include <font color=#004488>"Sorted.h"</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#009900>// Explicit instantiation:</font>
<font color=#0000ff>template</font> <font color=#0000ff>class</font> Sorted<<font color=#0000ff>int</font>>;
<font color=#0000ff>int</font> main() {
Sorted<<font color=#0000ff>int</font>> is;
Urand<47> rand1;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> k = 0; k < 15; k++)
is.push_back(rand1());
is.sort();
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> l = 0; l < is.size(); l++)
cout << is[l] << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In this example, the explicit
instantiation doesn’t really accomplish anything; the program would work
the same without it. Explicit instantiation is only for special cases where
extra control is needed.</FONT><A NAME="_Toc519041999"></A><BR></P></DIV>
<A NAME="Heading178"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Explicit specification of template functions<A NAME="_Toc519042000"></A></H3></FONT>
<A NAME="Heading179"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Controlling template instantiation</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Normally templates are not instantiated
until they are needed. For function templates this just means the point at which
you call the function, but for class templates it’s more granular than
that: each individual member function of the template is not instantiated until
the first point of use. This means that only the member functions you actually
use will be instantiated, which is quite important since it allows greater
freedom in what the template can be used with. For example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:DelayedInstantiation.cpp</font>
<font color=#009900>// Member functions of class templates are not</font>
<font color=#009900>// instantiated until they're needed.</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#0000ff>class</font> X {
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> f() {}
};
<font color=#0000ff>class</font> Y {
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> g() {}
};
<font color=#0000ff>template</font> <<font color=#0000ff>typename</font> T> <font color=#0000ff>class</font> Z {
T t;
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> a() { t.f(); }
<font color=#0000ff>void</font> b() { t.g(); }
};
<font color=#0000ff>int</font> main() {
Z<X> zx;
zx.a(); <font color=#009900>// Doesn't create Z<X>::b()</font>
Z<Y> zy;
zy.b(); <font color=#009900>// Doesn't create Z<Y>::a()</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, even though the template purports
to use both <B>f( )</B> and <B>g( )</B> member functions of <B>T</B>,
the fact that the program compiles shows you that it only generates
<B>Z<X>::a( )</B> when it is explicitly called for <B>zx</B> (if
<B>Z<X>::b( )</B> were also generated at the same time, a
compile-time error message would be generated). Similarly, the call to
<B>zy.b( )</B> doesn’t generate <B>Z<Y>::a( )</B>. As a
result, the <B>Z</B> template can be used with
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -