1. Parse a correct template class
(1) First, we want to create a template that can first design its behavior for a particular type parameter, and then generalize the general type of abstraction. For example, we can first design the concrete implementation of the String<char> class, and then generalize to the String<c> class template.
(2) The name of the class template cannot be overloaded. Therefore, if you declare a class template within a scope, you cannot have other entities of the same name.
template<classclass string{/* ... */ }; class String {/*... */}; // error: Duplicate definition
(3) When we instantiate a template, we just need to generate the template instance function code we used in the code:
string<char> cs; void f () { <Jchar> js; " Hello word! " ;}
In this code, only declarations of string<char> and string<jchar> are generated, and their corresponding srep types, default constructors and destructors, and string<char>::operator= ( char *), the other member functions are not used and are not generated.
(4) Template parameters. A template parameter can be used to make a constant expression, with an externally connected object or function address, or a non-overloaded pointer to a member. The pointer used for the template parameter must have a &of form, where the of must be the name of the object or function. A pointer to a member must have a &x::of form, of which is a member name. In particular, string constants cannot be used as template parameters. In addition, integer parameters are generally used to provide size or bounds:
template<classint i>class buffer{ T v[i]; // ...};
(5) Type check. The name in the template definition must be in scope, or depend on the template parameters in a reasonable and definite way. In addition, the error on template parameter usage can only be checked when the template is used.
2. Function templates
(1) automatic inference of type. For a function template, the compiler can infer the type parameter and the non-type parameter from one invocation, as the parameter list of a function call can uniquely identify a collection of type parameters. However, the compiler will never automatically infer the type for the template class, because a class may have more than one constructor, so automatic inference is unclear about the specific template parameter type. Explicit descriptions are often used in template functions, and the most common use of explicit descriptions is to provide return values for template functions:
template<classclass u> T implict_cast (U u) {return u;} int 1 ; Implict_cast<double> (i); // T is double, u is intimpict_cast<chardouble> (i); // T is char,u is double
(2) The parsing rules of template functions, we use a concrete example to understand:
template<class t> T sqrt (T T); Template <class t> complex<t> sqrt (complex<t> T); double sqrt (double b); complex <double > Z;sqrt ( 2 ); // sqrt<int> (int) sqrt (2.0 ); // sqrt (double) sqrt (z); // sqrt<double> (complex<double>)
--Find out the specialization of a set of function templates that can participate in this overload resolution. For example sqrt (z), produces sqrt<double> (complex<double>) and sqrt<complex<double> > (complex<double> )。
--Select the function template with the highest degree of specialization. This means that sqrt (z) chooses sqrt<double> (complex<double>). Because any match sqrt<t> (complex<t>) matches sqrt<t> (T).
--To do overload resolution, you should consider the general function at the same time. If a template parameter has been automatically inferred, you cannot match a regular function by type conversion. For sqrt (2), select sqrt<int> (int) instead of sqrt (double).
--If a function is as good as a specialization, then select the function. SQRT (2.0) selected sqrt (double) instead of sqrt<double> (double).
--not finding a match is a mistake. Either eliminate ambiguity by explicit invocation, or add an appropriate declaration.
3. How to describe a policy with template parameters
Let's look at a sort instance first. The sort rules we use are basically the same, but if the names of the Swedes are sort of special, then we have to make a separate collation that applies it to the function template:
template<classT>classcmp{Static intEQ (t A, T b) {returnA = =b;} Static intLt (t A, T b) {returnA <b;} Static intGT (t A, T b) {returnA >b;} };classliterate{Static inteqCharACharb) {returna==b;} Static intLtChar,Char){//...} //check a table based on character values};template<classTclassC = cmp<t> >intCompareConstString<t> &a,ConstString<t> &b) { for(inti =0; i < a.length () && i < b.length (); i++){ if(! C::eq (A[i], b[i]))returnC::lt (A[i], b[i])? -1:1; returnA.length ()-b.length ();}//calledvoidF (string<Char> A, string<Char>b) {Compare (A, b); //with cmp<char>compare<Char, literate>;//with Literate}
In the example, there are two advantages to passing the comparison operation as a template parameter: First, you can pass a few operations through one parameter, and the other is the overhead of no runtime.
4. Specialization
In the template, we may need different implementations for different template parameters, so we need to specialize to make a specific type of template implementation. Specialization provides different implementations for different parameters for a common interface. Note that the template itself and the specialization must be in the same namespace, the generic template must be declared before the specialized template, and the invocation using the specialization must also be scoped to the specialized template.
The following example implements the specialization of a pointer container:
//Generic Templatestemplate<classT>classvector{/*...*/};//template specialization for void*Template<>classvector<void*>{ void**p; //... void*operator[](inti);};//partial specialization for t*template<classT>classVector<t*>:Privatevector<void*>{ Public: typedef Vector<void*>Base; Vector (): Base () {}ExplicitVector (inti): Base (i) {} T*& Elem (inti) {returnReinterpret_cast<t*&>(Base::elem (i));} T*&operator[](inti) { returnReinterpret_cast<t*&>(base::operaotr[] (i)); } };
Derive a template class from a non-template class, which is a way to provide a common implementation for a set of templates.
5. Derivation and template
(1) We implement a container class, how to separate the container from the operation, the first method is through inheritance, the parent class template parameter type is a subclass:
template<classT>classbase_ops{ Public: BOOL operator==(Constt&)Const; BOOL operator!=(Constt&)Const; //permission to access the T operation Constt& Derived ()Const{returnstatic_cast<ConstT&> (* This);} //...};template<classT>Math_container: Publicbase_ops<math_container<t> >{ Public: size_t size ()Const; T&operator[] (size_t i); Constt&operator[] (size_t i)Const; //...};
The second approach is to combine containers and operations with the last-class parameters:
template<classTclassC>classmcontainer{C elements; Public: T&operator[] (size_t i) {returnelements[i];} FriendBOOL operator==(ConstMcontainer&,Constmcontainer&); FriendBOOL operator!=(ConstMcontainer&,Constmcontainer&);}; Template<classT>classmy_array{/*...*/}; Mcontainer<Double, my_array<Double> > mc;
(2) A class can contain a member that is itself a template:
template<class s>class complex{ S Re, im; Template<class t> Complex (const complex<t> &C): Re (C.real ( )), Im (C.imag ()) {} //... };complex<float> F (0.0); complex<double// can: There are conversions of float to double
However, the template constructor is not used to generate the copy constructor and assignment operators, so you must define the copy constructor and assignment operator yourself.
(3) There is no relationship between the two classes generated by the same template.
classshape{/*...*/};classCircle: Publicshape{/*...*/};classTriangle: Publicshape{/*...*/};voidFSet<Shape*> &R) {S.insert (NewTriangle ());}voidGSet<Circle*> &s) {f (s); //error: Type mismatch,set<circle*> not set<shape*>}
We must ensure that the members of the set<circle*> must be Circle, and if Set<circle*> is regarded as set<shape*>, we will not be guaranteed because set<shape*> Allow the insertion of the triangle type if set<shape*> is actually a set<circle*> then we destroy the set<circle*> members must be the basic guarantee of Circle.
The road to coding--re-learning C + + (8): Magical templates