📄 index.html
字号:
<pre>
<tt>template <class T, const char *> class A</tt>
<tt>{/*...*/};</tt>
<tt>void array_user()</tt>
<tt>{</tt>
<tt> const char * p ="illegal";</tt>
<tt> A<int, "invalid"> aa; // error, string literal used as a template argument</tt>
<tt> A<int, p> ab; // also an error, p doesn't have external linkage </tt>
<tt>}</tt>
</pre>
<p>A template can take a template as an argument. For example</p>
<pre>
<tt>int send(const Vector<char*>& );</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> Vector <Vector<char*> > msg_que(10); //a template used as an argument</tt>
<tt> //...fill msg_que</tt>
<tt> for (int i =0; i < 10; i++) //transmit messages</tt>
<tt> send(msg_que[i]);</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>Note that when a template is used as an argument, the space between the left
two angular brackets is mandatory:</p>
<pre>
<tt>Vector <Vector<char*> > msg_que(10);</tt>
</pre>
<p>Otherwise, the <tt>>></tt> sequence is parsed as the right shift operator.</p>
<p>A <tt>typedef</tt> can be used to avert this mishap and improve readability,
both for the compiler and for the human reader:</p>
<pre>
<tt>typedef Vector<char *> msg;</tt>
<tt>Vector<msg> msg_que;</tt>
</pre>
<h3> <a name="Heading6">Default Type Arguments</a></h3>
<p>Class templates can have default type arguments. </p>
<p>As with default argument values of a function, the default type of a template
gives the programmer more flexibility in choosing the optimal type for a particular
application. For instance, the <tt>Vector</tt> template can be optimized for
special memory management tasks. Instead of using the hard-coded <tt>size_t</tt>
type for storing the size of a <tt>Vector</tt>, it can have a size type as a
parameter. For most purposes, the default type <tt>size_t</tt> is used. However,
for managing extremely large memory buffers on the one hand -- or very small
ones on the other hand -- the programmer is free to choose other suitable data
types instead. For example</p>
<pre>
<tt>template <class T, class S = size_t > class Vector</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> S sz;</tt>
<tt> T * buff;</tt>
<tt>public:</tt>
<tt> explicit Vector(S s = 100): sz(s), buff(new T[s]){}</tt>
<tt> ~Vector();</tt>
<tt> //other member functions</tt>
<tt> S size() const;</tt>
<tt>};</tt>
<tt>template <class T, class S> Vector<T,S>::~Vector<T,S>()//destructor definition</tt>
<tt>{</tt>
<tt> delete [] buff;</tt>
<tt>}</tt>
<tt>template <class T, class S> S Vector<T,S>::size() const</tt>
<tt>{</tt>
<tt> return sz;</tt>
<tt>}</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> Vector <int> ordinary;</tt>
<tt> Vector <int, unsigned char> tiny(5);</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>An additional advantage of a default size type is the capability to support
implementation-dependent types. On a machine that supports 64-bit integers,
for instance, programmers can use <tt>Vector</tt> to easily manipulate very
large memory buffers: </p>
<pre>
<tt>Vector <int, unsigned __int64> very_huge; </tt>
</pre>
<p>The fact that the programmer does not have to make any changes to the definition
of <tt>Vector</tt> to get the appropriate specialization cannot be overemphasized.
Without templates, such a high level of automation is very difficult to achieve.</p>
<h3> <a name="Heading7">Static Data Members</a></h3>
<p>Templates can have static data members. For example</p>
<pre>
<tt>template<class T> class C</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> static T stat;</tt>
<tt>};</tt>
<tt>template<class T> T C<T>::stat = 5; //definition</tt>
</pre>
<p>A static data member can be accessed as follows:</p>
<pre>
<tt>void f()</tt>
<tt>{</tt>
<tt> int n = C<int>::stat;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading8">Friendship</a></h3>
<p>A friend of a class template can be a function template or class template,
a specialization of a function template or class template, or an ordinary (nontemplate)
function or class. The following sections discuss the various types of friendship
that a class template can have. </p>
<h4> Nontemplate Friends </h4>
<p>Nontemplate friend declarations of a class template look quite similar to friend
declarations of a nontemplate class. In the following example, the class template
<tt>Vector</tt> declares the ordinary function <tt>f()</tt> and class <tt>Thing</tt>
as its friends:</p>
<pre>
<tt>class Thing;</tt>
<tt>template <class T> class Vector</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> //...</tt>
<tt> friend void f ();</tt>
<tt> friend class Thing;</tt>
<tt>};</tt>
</pre>
<p>Each specialization of <tt>Vector</tt> has the function <tt>f()</tt> and class
<tt>Thing</tt> as friends. </p>
<h4> Specializations</h4>
<p>You can declare a specialization as a friend of a class template. In the following
example, the class template <tt>Vector</tt> declares the specialization <tt>C<void*></tt>
as its friend:</p>
<pre>
<tt>template <class T> class C{/*...*/};</tt>
<tt>template <class T> class Vector</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> //...</tt>
<tt> friend class C<void*>; //other specializations are not friends of Vector</tt>
<tt>};</tt>
</pre>
<h4> Template Friends</h4>
<p>A friend of a class template can be a template by itself. For instance, you
can declare a class template as a friend of another class template:</p>
<pre>
<tt>template <class U> class D{/*...*/};</tt>
<tt>template <class T> class Vector</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> //...</tt>
<tt> template <class U> friend class D;</tt>
<tt>};</tt>
</pre>
<p>Every specialization of <tt>D</tt> is a friend of every specialization of <tt>Vector</tt>.
You can also declare a function template as a friend (function templates will
be discussed in further detail shortly). For instance, you might add an overloaded
operator <tt>==</tt> function template to test the equality of two <tt>Vector</tt>
objects. Consequently, for every specialization of <tt>Vector</tt>, the implementation
will generate a corresponding specialization of the overloaded operator <tt>==</tt>.
In order to declare a friend template function, you first have to forward declare
the class template and the friend function template as follows:</p>
<pre>
<tt>template <class T> class Vector; // class template forward declaration</tt>
<tt> // forward declaration of the function template to be used as a friend</tt>
<tt>template <class T> bool operator== (const Vector<T>& v1, const Vector<T>& v2);</tt>
</pre>
<p>Next, the friend function template is declared inside the class body:</p>
<pre>
<tt> </tt>
<tt>template <class T> class Vector</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> //...</tt>
<tt> friend bool operator==<T> (const Vector<T>& v1, const Vector<T>& v2); </tt>
<tt>};</tt>
</pre>
<p>Finally, the friend function template is defined as follows:</p>
<pre>
<tt>template <class T> bool operator== (const Vector<T>& v1, const Vector<T>& v2)</tt>
<tt>{</tt>
<tt>// two Vectors are equal if and only if:</tt>
<tt>// 1) they have the same number of elements;</tt>
<tt>// 2) every element in one Vector is identical to the</tt>
<tt>// corresponding element in the second one</tt>
<tt> if (v1.size() != v2.size())</tt>
<tt> return false;</tt>
<tt> for (size_t i = 0; i<v1.size(); i++)</tt>
<tt> {</tt>
<tt> if(v1[i] != v2[i])</tt>
<tt> return false;</tt>
<tt> }</tt>
<tt> return true;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading9">Partial Specialization</a></h3>
<p>It is possible to define a <i>partial specialization</i> of a class template.
A partial specialization provides an alternative definition of the <i>primary
template</i>. It is used instead of the primary definition when the arguments
in any specialization match those that are given in the partial specialization.
For instance, a partial specialization of <tt>Vector</tt> can handle pointer
types exclusively. Thus, for specializations of fundamental types and user-defined
types, the primary <tt>Vector</tt> class is used. For pointers, the partial
specialization is used instead of the primary class template. A pointer partial
specialization can optimize the manipulation of pointers in several ways. </p>
<p>In addition, some operations that manipulate pointers involve dereferencing
and the use of operator <tt>-></tt>, neither of which is used with non-pointer
types.</p>
<p>A partial specialization is defined as follows:</p>
<pre>
<tt>//filename: Vector.hpp</tt>
<tt>template <class T> class Vector <T*> //partial specialization of Vector <T></tt>
<tt>{</tt>
<tt>private:</tt>
<tt> size_t size;</tt>
<tt> void * p;</tt>
<tt>public:</tt>
<tt> Vector();</tt>
<tt> ~Vector();</tt>
<tt> //...member functions</tt>
<tt> size_t size() const;</tt>
<tt>};</tt>
<tt>//Vector.hpp</tt>
</pre>
<p>A partial specialization is indicated by the parameter list that immediately
follows the class template name (remember that the primary template is declared
without the list after its name). Compare these two forms:</p>
<pre>
<tt> template <class T> class Vector //primary template</tt>
<tt>{}; </tt>
<tt>template <class T> class Vector <T*> //partial specialization</tt>
<tt>{};</tt>
</pre>
<p>Partial specializations of a class template that has several parameters are
declared as follows:</p>
<pre>
<tt>template<class T, class U, int i> class A { }; // primary</tt>
<tt>template<class T, int i> class A<T, T*, i> { }; // partial specialization</tt>
<tt>template<class T> class A<int, T*, 8> { }; // another partial specialization</tt>
<tt>Partial specializations must appear after the primary declaration of a class template, and its parameter cannot contain default types.</tt>
</pre>
<h3> <a name="Heading10">Explicit Specialization of a Class Template</a></h3>
<p>An <i>explicit specialization</i> of a class template provides an alternative
definition of the primary template. It is used instead of the primary definition
if the arguments in a particular specialization match those that are given in
the explicit specialization. When is it useful? Consider the <tt>Vector</tt>
template: The code that is generated by the compiler for the specialization
<tt>Vector<bool></tt> is very inefficient. Instead of storing every Boolean
value in a single bit, it occupies at least an entire byte. When you are manipulating
large amounts of bits, for example in logical operations or digital signal processing,
this is unacceptable. In addition, bit-oriented operations can be performed
more efficiently using the bitwise operators. Obviously, there are significant
advantages to defining a <tt>Vector</tt> template that is specifically adjusted
to manipulate bits. Following is an example of an explicit specialization <tt>Vector<bool>
</tt>that manipulates bits rather than bytes:</p>
<pre>
<tt>template <> class Vector <bool> //explicit specialization</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> size_t sz;</tt>
<tt> unsigned char * buff;</tt>
<tt>public:</tt>
<tt> explicit Vector(size_t s = 1) : sz(s), </tt>
<tt> buff (new unsigned char [(sz+7U)/8U] ) {}</tt>
<tt> Vector<bool> (const Vector <bool> & v); </tt>
<tt> Vector<bool>& operator= (const Vector<bool>& v); </tt>
<tt> ~Vector<bool>(); </tt>
<tt> //other member functions</tt>
<tt> bool& operator [] (unsigned int index);</tt>
<tt> const bool& operator [] (unsigned int index) const;</tt>
<tt> size_t size() const;</tt>
<tt>};</tt>
<tt>void bitmanip() </tt>
<tt>{</tt>
<tt> Vector< bool> bits(8);</tt>
<tt> bits[0] = true; //assign</tt>
<tt> bool seventh = bits[7]; //retrieve</tt>
<tt>}</tt>
</pre>
<p>The <tt>template<></tt> prefix indicates an explicit specialization of
a primary template. The template arguments for a specialization are specified
in the angular brackets that immediately follow the class name. The specialization
hierarchy of <tt>Vector</tt> that has been defined thus far is as follows:</p>
<pre>
<tt>template <class T> class Vector //primary template</tt>
<tt>{};</tt>
<tt>template <class T> class Vector <T*> //partial specialization</tt>
<tt>{};</tt>
<tt>template <> class Vector <bool> //explicit specialization</tt>
<tt>{};</tt>
</pre>
<p>Fortunately, the Standard Template Library already defines a specialization
of <tt>std::vector<bool></tt> for manipulating bits optimally, as you
will read in the next chapter, "STL and Generic Programming."</p>
<h3> <a name="Heading11">Specializations of Class Template Functions</a></h3>
<p>The overloaded operator <tt>==</tt> of class <tt>Vector</tt> performs a plausible
comparison between two <tt>Vector</tt> objects when their elements are either
fundamental types or objects that overload operator <tt>==</tt>. However, a
comparison of two objects that store <tt>C</tt> strings is likely to yield the
wrong result. For example</p>
<pre>
<tt>#include "Vector.hpp"</tt>
<tt>extern const char msg1[] = "hello";</tt>
<tt>extern const char msg2[] = "hello";</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> Vector<const char *> v1(1), v2(1); //the same number of elements</tt>
<tt> v1[0] = msg1;</tt>
<tt> v2[0] = msg2;</tt>
<tt> bool equal = (v1 == v2); //false, strings are equal but pointers aren't </tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -