📄 chap06.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source:
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:C:\TEMP\TicV2\html\TicV2.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/26/2001
Translation Time:08:32:26
Translation Platform:Win32
Number of Output files:19
This File:C:\TEMP\TicV2\html\Chap06.htm
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>6: Templates in depth</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
<a href="http://www.MindView.net">
<img src="mindview.gif" alt="MindView Inc." BORDER = "0"></a>
<CENTER>
<FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
[ <a href="README.txt">Viewing Hints</a> ]
[ <a href="RevisionHistory.htm">Revision History</a> ]
[ <a href="http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html">Book Home Page</a> ]
[ <a href="http://www.mindview.net/Etc/MailingList.html">Free Newsletter</a> ] <br>
[ <a href="http://www.mindview.net/Seminars">Seminars</a> ]
[ <a href="http://www.mindview.net/CDs">Seminars on CD ROM</a> ]
[ <a href="http://www.mindview.net/Services">Consulting</a> ]
</FONT>
<H2><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
Thinking in C++, 2nd edition, Volume 2<br>
<small>Revision 4.0</small></FONT></H2>
<H3><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
by Bruce Eckel & Chuck Allison<br>©2001 MindView, Inc.</FONT></H3>
<FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
[ <a href="Chap05.htm">Previous Chapter</a> ]
[ <a href="SimpCont.htm">Short TOC</a> ]
[ <a href="Contents.htm">Table of Contents</a> ]
[ <a href="DocIdx.htm">Index</a> ]
[ <a href="Chap07.htm">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc305593285"></A><A NAME="_Toc305628757"></A><A NAME="_Toc312374096"></A><A NAME="_Toc519041974"></A><A NAME="Heading151"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H1 ALIGN="LEFT">
6: Templates in depth</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>Intro stuff</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">intro
stuff</FONT><A NAME="AdvancedTemplatesChapter"></A><A NAME="_Toc519041975"></A><BR></P></DIV>
<A NAME="Heading152"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Nontype template arguments</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here is a random number generator class
that always produces a unique number and overloads <B>operator( )</B> to
produce a familiar function-call syntax:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Urand.h</font>
<font color=#009900>// Unique random number generator</font>
#ifndef URAND_H
#define URAND_H
#include <cstdlib>
#include <ctime>
<font color=#0000ff>template</font><<font color=#0000ff>int</font> upperBound>
<font color=#0000ff>class</font> Urand {
<font color=#0000ff>int</font> used[upperBound];
<font color=#0000ff>bool</font> recycle;
<font color=#0000ff>public</font>:
Urand(<font color=#0000ff>bool</font> recycle = <font color=#0000ff>false</font>);
<font color=#0000ff>int</font> <font color=#0000ff>operator</font>()(); <font color=#009900>// The "generator" function</font>
};
<font color=#0000ff>template</font><<font color=#0000ff>int</font> upperBound>
Urand<upperBound>::Urand(<font color=#0000ff>bool</font> recyc)
: recycle(recyc) {
memset(used, 0, upperBound * <font color=#0000ff>sizeof</font>(<font color=#0000ff>int</font>));
srand(time(0)); <font color=#009900>// Seed random number generator</font>
}
<font color=#0000ff>template</font><<font color=#0000ff>int</font> upperBound>
<font color=#0000ff>int</font> Urand<upperBound>::<font color=#0000ff>operator</font>()() {
<font color=#0000ff>if</font>(!memchr(used, 0, upperBound)) {
<font color=#0000ff>if</font>(recycle)
memset(used,0,<font color=#0000ff>sizeof</font>(used) * <font color=#0000ff>sizeof</font>(<font color=#0000ff>int</font>));
<font color=#0000ff>else</font>
<font color=#0000ff>return</font> -1; <font color=#009900>// No more spaces left</font>
}
<font color=#0000ff>int</font> newval;
<font color=#0000ff>while</font>(used[newval = rand() % upperBound])
; <font color=#009900>// Until unique value is found</font>
used[newval]++; <font color=#009900>// Set flag</font>
<font color=#0000ff>return</font> newval;
}
#endif <font color=#009900>// URAND_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The uniqueness of <B>Urand</B> is
produced by keeping a map of all the numbers possible in the random space (the
upper bound is set with the template argument) and marking each one off as
it’s used. The optional constructor argument allows you to reuse the
numbers once they’re all used up. Notice that this implementation is
optimized for speed by allocating the entire map, regardless of how many numbers
you’re going to need. If you want to optimize for size, you can change the
underlying implementation so it allocates storage for the map dynamically and
puts the random numbers themselves in the map rather than flags. Notice that
this change in implementation will not affect any client
code.</FONT><A NAME="_Toc519041976"></A><BR></P></DIV>
<A NAME="Heading153"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Default template arguments<A NAME="_Toc519041977"></A></H2></FONT>
<A NAME="Heading154"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
The typename keyword</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Consider the following:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:TypenamedID.cpp</font>
<font color=#009900>// Using 'typename' to say it's a type, </font>
<font color=#009900>// and not something other than a type</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T> <font color=#0000ff>class</font> X {
<font color=#009900>// Without typename, you should get an error:</font>
<font color=#0000ff>typename</font> T::id i;
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> f() { i.g(); }
};
<font color=#0000ff>class</font> Y {
<font color=#0000ff>public</font>:
<font color=#0000ff>class</font> id {
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> g() {}
};
};
<font color=#0000ff>int</font> main() {
Y y;
X<Y> xy;
xy.f();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The template definition assumes that the
class <B>T</B> that you hand it must have a nested identifier of some kind
called <B>id</B>. But <B>id</B> could be a member object of <B>T</B>, in which
case you can perform operations on <B>id </B>directly, but you couldn’t
“create an object” of “the type <B>id</B>.” However,
that’s exactly what is happening here: the identifier <B>id </B>is being
treated as if it were actually a nested type inside <B>T</B>. In the case of
class <B>Y</B>, <B>id</B> is in fact a nested type, but (without the <B>typename
</B>keyword) the compiler can’t know that when it’s compiling
<B>X</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If, when it sees an identifier in a
template, the compiler has the option of treating that identifier as a type or
as something other than a type, then it will assume that the identifier refers
to something other than a type. That is, it will assume that the identifier
refers to an object (including variables of primitive types), an enumeration or
something similar. However, it will not – cannot – just assume that
it is a type. Thus, the compiler gets confused when we pretend it’s a
type.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>typename</B> keyword tells the
compiler to interpret a particular name as a type. It must be used for a name
that:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Is a qualified name, one
that is nested within another
type.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Depends on a
template argument. That is, a template argument is somehow involved in the name.
The template argument causes the ambiguity when the compiler makes the simplest
assumption: that the name refers to something other than a
type.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because the default
behavior of the compiler is to assume that a name that fits the above two points
is not a type, you must use <B>typename</B> even in places where you think that
the compiler ought to be able to figure out the right way to interpret the name
on its own. In the above example, when the compiler sees <B>T::id</B>, it knows
(because of the <B>typename</B> keyword) that <B>id</B> refers to a nested type
and thus it can create an object of that type.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The short version of the rule is: if your
type is a qualified name that involves a template argument, you must use
<B>typename</B>.</FONT><A NAME="_Toc519041978"></A><BR></P></DIV>
<A NAME="Heading155"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Typedefing a typename</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>typename</B> keyword does not
automatically create a <B>typedef</B>. A line which reads:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typename</font> Seq::iterator It;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">causes a variable to be declared of type
<B>Seq::iterator</B>. If you mean to make a <B>typedef</B>, you must
say:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typedef</font> <font color=#0000ff>typename</font> Seq::iterator It;</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><A NAME="_Toc519041979"></A><BR></P></DIV>
<A NAME="Heading156"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Using typename instead of class</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">With the introduction of the
<B>typename</B> keyword, you now have the option of using <B>typename</B>
instead of <B>class</B> in the template argument list of a template definition.
This may produce code which is clearer:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:UsingTypename.cpp</font>
<font color=#009900>// Using 'typename' in the template argument list</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#0000ff>template</font><<font color=#0000ff>typename</font> T> <font color=#0000ff>class</font> X { };
<font color=#0000ff>int</font> main() {
X<<font color=#0000ff>int</font>> x;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’ll probably see a great deal of
code which does not use <B>typename</B> in this fashion, since the keyword was
added to the language a relatively long time after templates were
introduced.</FONT><A NAME="_Toc305593282"></A><A NAME="_Toc305628754"></A><A NAME="_Toc312374089"></A><A NAME="_Toc519041980"></A><BR></P></DIV>
<A NAME="Heading157"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Function templates<BR><A NAME="Index466"></A><A NAME="Index467"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A class template describes an infinite
set of classes, and the most common place you’ll see templates is with
classes. However, C++ also supports the concept of an infinite set of functions,
which is sometimes useful. The syntax is virtually identical, except that you
create a function instead of a class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The clue that you should create a
function template is, as you might suspect, if you find you’re creating a
number of functions that look identical except that they are dealing with
different types. The classic example of a function template is a sorting
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -