📄 index.html
字号:
<tt> short int u = 5, v = 10;</tt>
<tt> short int w = min(u,v);</tt>
<tt>}</tt>
</pre>
<p>Still, the template version of <tt>min</tt> has a clear advantage over the
function: It can handle pointers and any other user-defined types. You want
the benefits of a template while avoiding the unnecessary generation of specializations.
How can these be avoided? A simple solution is to safely cast the arguments
into one common type before invoking the function template. For example:</p>
<pre>
<tt>void no_proliferation()</tt>
<tt>{</tt>
<tt> short n = 5, m= 10;</tt>
<tt> int j = min( static_cast<int> (n), </tt>
<tt> static_cast<int> (m) ); //min<int> instantiated</tt>
<tt> char c = 'a', d = 'b';</tt>
<tt> char k = static_cast<char> (min( static_cast<int> , </tt>
<tt> static_cast<int> ) ); //min<int> used</tt>
<tt>}</tt>
</pre>
<p>This technique can also be applied to pointers: First, they have to be cast
to <tt>void<b> </b>*</tt>, and then they must be cast back to their original
type. When you are using pointers to polymorphic objects, pointers to derived
objects are cast to pointers to a base class.</p>
<p>For very small templates such as <tt>min</tt>, casting the arguments into a
common denominator type is not worth the trouble. Nonetheless, when nontrivial
templates that contain hundreds of code lines are used, you might consider doing
so.</p>
<h3> <a name="Heading19">Explicit Template Instantiation</a></h3>
<p>As was previously noted, templates are instantiated only if they are used in
the program. Generally, compilers generate the necessary code for a specialization
when they encounter its use in the source file. When large applications that
consist of hundreds of source files have to be compiled, this can cause a significant
increase in compilation time because the compiler's processing is repeatedly
interrupted when it has to generate code for sporadic specializations. The recurrent
interruption can occur in almost every source file because they use -- almost
without exception -- template classes of the Standard Library. Consider a simple
project that consists of only three source files:</p>
<pre>
<tt>//filename func1.cpp</tt>
<tt>#include <string></tt>
<tt>#include <iostream></tt>
<tt>using namespace std;</tt>
<tt>void func1()</tt>
<tt>{</tt>
<tt> string s; //generate default constructor and destructor</tt>
<tt> s = "hello"; //generate assignment operator for const char *</tt>
<tt> string s2;</tt>
<tt> s2 = s; // generate operator = const string&, string&</tt>
<tt> cout<<s2.size(); // generate string::size, ostream& operator <<(int)</tt>
<tt>}</tt>
<tt>//func1.cpp</tt>
<tt>//filename func2.cpp</tt>
<tt>#include <string></tt>
<tt>#include <iostream></tt>
<tt>using namespace std;</tt>
<tt>void func2()</tt>
<tt>{</tt>
<tt> string s; //generate default constructor and destructor</tt>
<tt>cout<<"enter a string: "<<endl; //generate ostream& operator<<(const char *)</tt>
<tt> cin>>s //generate istream& operator>>(string&)</tt>
<tt>}</tt>
<tt>//func2.cpp</tt>
<tt>//filename main.cpp</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> func1();</tt>
<tt> func2();</tt>
<tt> retrun 0;</tt>
<tt>}</tt>
<tt>// main.cpp</tt>
</pre>
<p>The compilation time can be reduced if all the necessary template code is instantiated
all at once, thereby avoiding the repeated interruption of the compiler's processing.
For this purpose, you can use an <i>explicit instantiation</i>. An explicit
instantiation is indicated by the keyword <tt>template</tt> (without the <tt><></tt>),
followed by a template declaration.<b> </b>Here are a few examples of explicit
template instantiations:</p>
<pre>
<tt>template <class T> class A{/*..*/};</tt>
<tt>template<class T> void func(T&) { }</tt>
<tt> //filename instantiations.hpp</tt>
<tt>template class Vector<short>; //explicit instantiation of a class template</tt>
<tt>template A<int>::A<int>(); //explicit instantiation of a member function</tt>
<tt>template class </tt>
<tt> std::basic_string<char>; //explicit instantiation of a namespace member</tt>
<tt>template void func<int>(int&); //explicit instantiation of a function template</tt>
</pre>
<h4> Examples of Explicit Instantiations in the Standard Library</h4>
<p>The Standard Library defines several specializations of class templates. One
example is the class template <tt>basic_string<></tt>. Two specialized
versions of this class are <tt>std::string</tt> and <tt>std::wstring</tt>, which
are <tt>typedef</tt>s of the specializations <tt>basic_string<char></tt>
and <tt>basic_string<wchar_t></tt>, respectively. Usually, there is no
need to instantiate any of these explicitly because the header <tt><string></tt>
already instantiates these specializations:</p>
<pre>
<tt>#include <string> //definitions of std::string and std::wstring</tt>
<tt>using namespace std;</tt>
<tt>bool TranslateToKorean(const string& origin, </tt>
<tt> wstring& target ); //English / Korean dictionary</tt>
<tt> int main()</tt>
<tt> {</tt>
<tt> string EnglishMsg = "This program has performed an illegal operation";</tt>
<tt> wstring KoreanMsg;</tt>
<tt> TranslateToKorean(EnglishMsg, KoreanMsg);</tt>
<tt> }</tt>
</pre>
<h3> <a name="Heading20"> Exported Templates</a></h3>
<blockquote>
<hr>
<strong>NOTE: </strong> Exported templates are relatively new in C++; therefore,
not all compilers support this feature yet. Please consult your user's manual
to check whether your compiler supports it.
<hr>
</blockquote>
<p>A template definition can be <tt>#included</tt> in several translation units;
consequently, it can be compiled several times. As you have observed, this can
considerably increase compilation and linkage time. Instead of <tt>#including</tt>
a complete definition of the template, it is possible to compile the template
definition only once, and use only the template's declaration in other translation
units. This is very similar to the compilation of external functions and classes,
in which the definition is compiled only once and then only the declarations
are required.</p>
<p>To compile a template separately and then use its declaration, the template
has to be <i>exported</i>. This is done by preceding the template's definition
with the keyword <tt>export</tt>:</p>
<pre>
<tt>//filename min.cpp</tt>
<tt>export template < class T > T min (const T& a, const T& b)</tt>
<tt>{</tt>
<tt> return a > b ? b : a;</tt>
<tt>}</tt>
</pre>
<p>Now only the declaration of the template is required when it is used in other
translation units. For example</p>
<pre>
<tt> //file min.c</tt>
<tt>template < class T > T min (const T & a, const T & b); //declaration only</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> int j=0, k=1;</tt>
<tt> in smaller = min(j,k);</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>Inline function templates cannot be exported. If an inline template function
is declared both <tt>export</tt> and <tt>inline</tt>, the <tt>export</tt> declaration
has no effect and the template is only inline. Declaring a class template exported
is equivalent to declaring all its non-inline member functions, static data
members, and member classes exported. Templates in an unnamed namespace are
not to be exported.</p>
<h2> <a name="Heading21">Interaction with Other Language Features</a></h2>
<p>The interaction of templates with other language features can sometimes yield
surprising results. The following sections discuss various aspects of interaction
between templates and other language features, including ambiguous interpretation
of qualified template names, inheritance, and virtual member functions.</p>
<h3> <a name="Heading22">The typename Keyword</a></h3>
<p>Using qualified names in a template can cause ambiguity between a type and
a non-type. For example</p>
<pre>
<tt>int N;</tt>
<tt>template < class T > T func()</tt>
<tt>{</tt>
<tt> T::A * N; // ambiguous: multiplication or a pointer declaration?</tt>
<tt>//</tt>
<tt>}</tt>
</pre>
<p> If <tt>T::A</tt> is a typename, the definition of <tt>func() N</tt> creates
a pointer. If, on the other hand, <tt>T::A</tt> is a non-type (for example,
if <tt>A</tt> is data member of type <tt>int</tt>), <tt>T::A * N</tt> is an
expression statement that consists of the multiplication of the qualified member
<tt>T::A</tt> by a global <tt>int N</tt>. By default, the compiler assumes that
an expression such as <tt>T::A</tt> refers to a non-type. The <tt>typename</tt>
keyword instructs the compiler to supersede this default interpretation and
resolve the ambiguity in favor of a type name rather than a non-type. In other
words, the preceding (seemingly ambiguous) statement is actually resolved as
a multiplication expression, the result of which is discarded. In order to declare
a pointer, the <tt>typename</tt> keyword is required:</p>
<pre>
<tt>int N;</tt>
<tt>template < class T > T func()</tt>
<tt>{</tt>
<tt> typename T::A * N; // N is a now pointer since T::A is a typename</tt>
<tt>//...</tt>
<tt>};</tt>
</pre>
<h3> <a name="Heading23">Inheritance Relationship of Templates</a></h3>
<p>A common mistake is to assume that a container of pointers or references to
objects of a derived class is a container of pointers or references to a base
class. For example</p>
<pre>
<tt>#include<vector></tt>
<tt>using namespace std;</tt>
<tt>class Base</tt>
<tt>{</tt>
<tt>public: virtual void f() {}</tt>
<tt>};</tt>
<tt>class Derived : public Base</tt>
<tt>{</tt>
<tt>public: void f() {}</tt>
<tt>};</tt>
<tt>void func( vector<Base*>& vb);</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> Derived d;</tt>
<tt> vector<Derived*> vd;</tt>
<tt> vd.push_back(&d);</tt>
<tt> func(vd); //error, vector<Derived*>& is not a vector<Base*></tt>
<tt>}</tt>
</pre>
<p>Although the is-a relationship exists between the classes <tt>Derived</tt>
and <tt>Base</tt>, there is no such relationship between specializations of
the same class template that contain pointers or references to related objects.</p>
<h3> <a name="Heading24">Virtual Member Functions</a></h3>
<p>A member function template should not be virtual. However, ordinary member
functions in a class template <i>can</i> be virtual. For example</p>
<pre>
<tt>template <class T> class A</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> template <class S> virtual void f(S); //error</tt>
<tt> virtual int g(); // OK</tt>
<tt>};</tt>
</pre>
<p>A specialization of a member function template does not override a virtual
function that is defined in a base class. For example</p>
<pre>
<tt>class Base</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> virtual void f(char);</tt>
<tt>};</tt>
<tt>class Derived : public Base</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> template <class T> void f(T); //does not override B::f(int)</tt>
<tt>};</tt>
</pre>
<h3> <a name="Heading25">Pointers to Members of a Class Template</a></h3>
<p>Pointers to class members can take the address of a specialized member function
of a class template. As with ordinary classes, pointers to members cannot take
the address of a static member function. In the following example, the specialization
<tt>std::vector<int></tt> is used:</p>
<pre>
<tt>#include<vector></tt>
<tt>using namespace std;</tt>
<tt> // a typedef is used to hide the unwieldy syntax</tt>
<tt>typedef void (vector< int >::*pmv) (size_t);</tt>
<tt>void func()</tt>
<tt>{</tt>
<tt> pmv reserve_ptr = &vector< int >::reserve;</tt>
<tt> //...use reserve_ptr</tt>
<tt>}</tt>
</pre>
<h2> <a name="Heading26">Conclusions</a></h2>
<p>Templates simplify and streamline the implementation of generic containers
and functions. The benefits of templates have allured software vendors, who
are now migrating from plain object-oriented frameworks to object-oriented generic
frameworks. However, parameterized types are not unique to C++. Back in 1983,
Ada introduced generic packages, which were roughly equivalent to class templates.
Other languages implemented similar mechanisms of automated code generation
from a skeletal user-written code.</p>
<p>The two main template categories in C++ are class templates and function templates.
A class template encapsulates parameterized data members and function members.
Function templates are a means of implementing generic algorithms. The traditional
methods of implementing generic algorithms in pre-template C++ were rather limited,
unsafe, and inefficient compared to templates. An important aspect of templates
is the support of object semantics.</p>
<p>C++ enables programmers to control the instantiation of templates by explicitly
instantiating them. It is possible to instantiate an entire class, a certain
member function of a class, or a particular specialization of a function template.
An explicit instantiation of a template is indicated by the keyword <tt>template</tt>,
without angular brackets that are followed by the template declaration. Explicit
specializations of a class template are always required. For function templates,
the compiler usually deduces the specialization from the type of the arguments.
It is possible to define partial specialization of a class template that overrides
the primary class template for a set of types. This feature is most useful for
modifying the behavior of a class template that manipulates pointers. A partial
specialization is indicated by a secondary list of parameters following the
name of the template. An explicit specialization enables the programmer to override
the automatic instantiation of a class template for a certain type. An explicit
specialization is indicated by the keyword <tt>template</tt>, followed by empty
angular brackets and a list of type arguments after the template's name.</p>
<p>Templates and operator overloading are the building blocks of generic programming.
The Standard Template Library is an exemplary framework of generic programming,
as you will see in the next chapter.</p>
<CENTER>
<P>
<HR>
<A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR>
<BR>
<BR>
<p></P>
<P>© <A HREF="/publishers/que/series/professional/0789720221/copy.htm">Copyright 1999</A>, Macmillan Computer Publishing. All
rights reserved.</p>
</CENTER>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -