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

📄 ch09.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<pre><tt>template &lt;class T, const char *&gt; class A</tt><tt>{/*...*/};</tt><tt>void  array_user()</tt><tt>{</tt><tt>  const char * p ="illegal";</tt><tt>  A&lt;int, "invalid"&gt; aa;  // error, string literal used as a template argument</tt><tt>  A&lt;int, p&gt; 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&lt;char*&gt;&amp; );</tt><tt>int main()</tt><tt>{</tt><tt>  Vector &lt;Vector&lt;char*&gt; &gt; msg_que(10); //a template used as an argument</tt><tt>  //...fill msg_que</tt><tt>  for (int i =0; i &lt; 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 &lt;Vector&lt;char*&gt; &gt; msg_que(10);</tt></pre><p>Otherwise, the <tt>&gt;&gt;</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&lt;char *&gt; msg;</tt><tt>Vector&lt;msg&gt; 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 &lt;class T, class S = size_t &gt; 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 &lt;class T, class S&gt; Vector&lt;T,S&gt;::~Vector&lt;T,S&gt;()//destructor definition</tt><tt>{</tt><tt>  delete [] buff;</tt><tt>}</tt><tt>template &lt;class T, class S&gt; S Vector&lt;T,S&gt;::size() const</tt><tt>{</tt><tt>  return sz;</tt><tt>}</tt><tt>int  main()</tt><tt>{</tt><tt>  Vector &lt;int&gt; ordinary;</tt><tt>  Vector &lt;int, unsigned char&gt; 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 &lt;int, unsigned __int64&gt; 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&lt;class T&gt; class C</tt><tt>{</tt><tt>public:</tt><tt>  static T stat;</tt><tt>};</tt><tt>template&lt;class T&gt; T C&lt;T&gt;::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&lt;int&gt;::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 &lt;class T&gt; 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&lt;void*&gt;</tt>   as its friend:</p><pre><tt>template &lt;class T&gt; class C{/*...*/};</tt><tt>template &lt;class T&gt; class Vector</tt><tt>{</tt><tt>public:</tt><tt>  //...</tt><tt>  friend class C&lt;void*&gt;; //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 &lt;class U&gt; class D{/*...*/};</tt><tt>template &lt;class T&gt; class Vector</tt><tt>{</tt><tt>public:</tt><tt>  //...</tt><tt> template &lt;class U&gt; 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 &lt;class T&gt; class Vector; // class template forward declaration</tt><tt>  // forward declaration of the function template to be used as a friend</tt><tt>template &lt;class T&gt; bool operator== (const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; v2);</tt></pre><p>Next, the friend function template is declared inside the class body:</p><pre><tt> </tt><tt>template &lt;class T&gt; class Vector</tt><tt>{</tt><tt>public:</tt><tt>  //...</tt><tt>  friend bool operator==&lt;T&gt; (const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; v2); </tt><tt>};</tt></pre><p>Finally, the friend function template is defined as follows:</p><pre><tt>template &lt;class T&gt; bool operator== (const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; 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&lt;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>-&gt;</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 &lt;class T&gt; class Vector &lt;T*&gt; //partial specialization of Vector &lt;T&gt;</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 &lt;class T&gt; class Vector //primary template</tt><tt>{};   </tt><tt>template &lt;class T&gt; class Vector &lt;T*&gt; //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&lt;class T, class U, int i&gt; class A { };    // primary</tt><tt>template&lt;class T, int i&gt;  class A&lt;T, T*, i&gt;  { };    // partial specialization</tt><tt>template&lt;class T&gt;  class A&lt;int, T*, 8&gt; { };   // 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&lt;bool&gt;</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&lt;bool&gt;   </tt>that manipulates bits rather than bytes:</p><pre><tt>template &lt;&gt; class Vector &lt;bool&gt; //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&lt;bool&gt; (const Vector &lt;bool&gt; &amp; v);  </tt><tt>  Vector&lt;bool&gt;&amp; operator= (const Vector&lt;bool&gt;&amp; v); </tt><tt>  ~Vector&lt;bool&gt;(); </tt><tt>  //other member functions</tt><tt>  bool&amp; operator [] (unsigned int index);</tt><tt>  const bool&amp; operator [] (unsigned int index) const;</tt><tt>  size_t size() const;</tt><tt>};</tt><tt>void bitmanip()  </tt><tt>{</tt><tt> Vector&lt; bool&gt; bits(8);</tt><tt> bits[0] = true; //assign</tt><tt> bool seventh = bits[7]; //retrieve</tt><tt>}</tt></pre><p>The <tt>template&lt;&gt;</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 &lt;class T&gt; class Vector //primary template</tt><tt>{};</tt><tt>template &lt;class T&gt; class Vector &lt;T*&gt; //partial specialization</tt><tt>{};</tt><tt>template &lt;&gt; class Vector &lt;bool&gt; //explicit specialization</tt><tt>{};</tt></pre><p>Fortunately, the Standard Template Library already defines a specialization   of <tt>std::vector&lt;bool&gt;</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&lt;const char *&gt; 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 + -