Template and generic programming-template Specialization
Introduction:
We cannot always writeThe most suitable template for all types that may be instantiated. In some cases, the general template definition may be completely incorrect for a type, and the general template definition may not be compiled or incorrect. In other cases, you can use some special knowledge about types to compile functions that are more efficient than functions instantiated from templates.
The compare function and the Queue class are both good examples of this problem: they do not work correctly when used together with C-style strings.
Compare function template:
template
int compare(const Type &v1,const Type &v2){ if (v1 < v2) return -1; if (v2 < v1) return 1; return 0;}
If two constchar * parameters are used to call the template definition, the function compares the pointer value. It will tell us the relative positions of the two pointers in the memory,Nothing related to the content of the array indicated by the pointer.
To use the compare function for strings, you must provideComparisonCSpecial definition of style strings. These versions are special,This fact is true for the TemplateUser transparency. For users, calling a special function or using a special class is no different from using a version instantiated from a general template.
I. Specialization of function templates
Template specialization: the actual type or actual value of one or more template parameters in this definition is specified. The special form is as follows:
1) keyword template followed by an empty pair of angle brackets (<> );
2) then, the Template Name and a pair of angle brackets are followed. The angle brackets specify the specific template parameter;
3) function parameter table;
4) function body.
When the template parameter type is bound to const char *, the compare function features:
template<>int compare
(const char *const &v1, const char *const &v2){ return strcmp(v1,v2);}
The special declaration must match the corresponding template. When the compare function is called, two character pointers are passed to it, and the compiler will call the special version. The compiler calls the generic version for any other real parameter type (including common char:
const char *p1 = "Hello",*p2 = "world"; int i1,i2; cout << compare(p1,p2) << endl; cout << compare(i1,i2) << endl;
1, Declaration template special
Like any function,Function template specialization can be declared without definition.
template<>int compare
(const char *const &v1, const char *const &v2);
Template SpecializationMust always contain an empty template parameter description, That isTemplate<>, And alsoMust contain the function parameter table. If you can infer the template parameters from the function parameter table, you do not need to explicitly specify the template parameters:
int compare
(const char *const &v1, const char *const &v2);//Errortemplate<>int compare
;//OKtemplate<>int compare(const char *const &v1, const char *const &v2);//OK
2Function overloading and template Specialization
The omission of an empty template form parameter table template in the special process will produce surprising results. If the special syntax is missing, the result isDeclare the function to overload non-template versions:
Template <> int compare (const char * const & v1, const char * const & v2); int compare (const char * const & v1, const char * const & v2 ); // OK: But it is a non-template overload version!
When defining non-template functions,Apply regular conversions to real parameters; WhenSpecial TemplateWhenThe real parameter type is not converted.. In calling the template special version,The real parameter type must be the form parameter type of the special version function.Exact matchIf not, the compiler instantiates an instance for the real parameters defined in the template.
3Duplicate definitions are not always Detected
If a program consists of multiple files, the template-specific statement must appear in each file using the specific file. Cannot be defined from generalized templates in some filesInstantiate a function Template,In other files, this function version is specified for the real parameter set of the same template..
[Best practices]
Like other function declarationsThe header file contains the template-specific statement.And then use each of the special source files to include the file!
4General scope rules are used for special
Prior to being able to declare or define the specific template, the declaration of the specific template must be in the scope. Similarly, before calling the template version, the Special Declaration must be in the scope:
template
int compare(const Type &v1,const Type &v2){ cout << "generic" << endl; if (v1 < v2) return -1; if (v2 < v1) return 1; return 0;}int main(){ int i = compare("Hello","World");//print “generic”}template<>int compare
(const char *const &v1, const char *const &v2){ cout << "hah" << endl; return strcmp(v1,v2);}
This program has an error, because a call that can match the feature is made before the code is declared as special. When the compiler sees a function call, it must know that this version needs to be made special; otherwise, the compiler may instantiate the function from the template definition.
For the same template with the same template real parameter set, the program cannot be both explicit and instantiated.
This error occurs after the template instance is called..
// P567 exercise 16.52/53/54 template
Size_t count (const vector
& Vec, const ValType & val) {size_t appers = 0; for (typename vector
: Const_iterator iter = vec. begin (); iter! = Vec. end (); ++ iter) {if (* iter = val) {++ appers ;}} return appers ;}template <> size_t count (const vector
& Vec, const string & val); int main () {ifstream inFile ("input"); vector
Ivec; int val; while (inFile> val) {ivec. push_back (val);} while (cin> val) {cout <count (ivec, val) <endl ;}template <> size_t count (const vector
& Vec, const string & val) {size_t appers = 0; for (typename vector
: Const_iterator iter = vec. begin (); iter! = Vec. end (); ++ iter) {if (* iter = val) {++ appers ;}} return appers ;}
Ii. Special Template
When used as a C-style string, the Queue class has similar issues with the compare function. In this case, the problem lies in the push function. This function copies the value to create a new element in the Queue. By default, the C-style string is copied.Only the pointer is copied.,Do not copy characters. In this case, the replication pointer will have all the problems that share the pointer in other environments, the most serious is,If the Pointer Points to the dynamic memory,The user may delete the array indicated by the pointer..
1, Define special class
One way to provide correct behavior for the Queue of a C-style string is to define the special version of the entire class for constchar:
template<> class Queue
{public: void push(const char *); void pop() { real_queue.pop(); } bool empty() const { return real_queue.empty(); } std::string front() { return real_queue.front(); } const std::string front() const { return real_queue.front(); }private: Queue
real_queue;};
This implements a Queue data element: the Queue of the string object. Each memberAssign work to this Member.
This version of the Queue class does not define the replication control Member, which is uniqueThe data member is of the class type., This class type completes the correct work when it is copied, assigned, or revoked.You can use the merged copy control members..
This Queue class implements most of the same interfaces but not exactly the same as the template version of Queue. The difference is that the front member returns a string instead of a char *, to avoid having to manage character Arrays-if you want to return a pointer, you need a character array.
It is worth noting that:Specialization can define members that are completely different from the template itself.. If a specific member cannot be defined from the template,This member cannot be used for objects of this special type..Class template MemberIs not used to createExplicit special Member.
[Best practices]
Class template specialization should be defined with its specific templateSame interfaceOtherwise, users may be surprised when trying to use undefined members.
2,Class-specific definition
When a class-specific external definition member is added, the member cannot be marked with template <>.
void Queue
::push(const char *p){ return real_queue.push(p);}
Although this function does almost nothing, it implicitly copies the character array pointed to by val.Replication is performed onReal_queue.pushInThis call creates a new string object from the constchar * real parameter. The constchar * real parameter uses a string constructor with the constchar * parameter. The string constructor copies the characters in the array indicated by val to an untitled string object, this object will be stored in the elements pushed to real_queue.