Test environment:
Target:x86_64-linux-gnu
gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1)
What is generic programming? Why do C + + have templates? All of this is about how to write a general addition function.
A long, long time ago.
One person is going to write a general addition function, and he thinks of several ways:
- Using function overloading, re-implementing it for each of the different types of the same behavior you want
int Add (const int &_ileft, const int &_iright)
{
Return (_ileft + _iright);
}
float Add (const float &_fleft, const float &_fright)
{
Return (_fleft + _fright);
}
Of course inevitably have their own shortcomings:
- As long as a new type appears, it's too cumbersome to re-add the corresponding function.
- Code has a low re-use rate
- function overloading cannot be resolved if the function simply returns a value type (the condition of the function Overload: same scope, same function name, different parameter list)
- One method has a problem, all the methods have problems, not good maintenance
- Use common base classes to put common code in common base classes
Disadvantages
1, the use of common base class to write common code, will lose the advantages of type checking
2, for many of the later implementation of the class, must inherit from a particular base class, code maintenance more difficult
#define ADD (A, B) ((a) + (b))
- No parameter type detection, no high security
- Compile preprocessing phase complete replacement, debugging inconvenience
Therefore, the concept of generic programming is introduced in C + +. Generic programming is the writing of type-independent code. This is a means of code reuse. Templates are the basis of generic programming.
Templates are divided into function templates and class templates:
function templates
Function Template: Represents a function family, which is independent of the type, is parameterized when used, and produces a specific type version of the function based on the argument type.
What do you mean? Look down and you'll find out.
Format of template functions
Template<typename Param1, TypeName Param2,..., class paramn>
return value type function name (parameter list)
{
...
}
A simple Add function template:
Template <typename t>//t but his own name, satisfies the naming specification can T ADD (t left, t right) {return left + right;} int main () {Add (1, 2);//right Call this function is to add (1, 2.0);//error has only one type T, passing two different type parameters cannot determine the type of template parameter T, compile error return 0;}
For the first function call, the compiler generates a function such as int add<int> (int, int).
TypeName is used to define template parameter keywords, or you can use class. However, it is recommended to use TypeName as much as possible, because this keyword is made for templates!
Note: You cannot use structs instead of TypeName. (The class here is not the meaning of the previous class, so you know)
Of course you can also declare a function template inline:
Template <typename t>
Inline T Add (t left, t right) {//...}
Instantiation of
A compiler produces a specific type version of a specified class or function with a template, and the process of producing a template-specific type is called a function template instantiation . (Creating an object with a class type is also called instantiation!) )
Compilation of templates
The template was compiled two times:
- Before instantiating, check the template code itself to see if there is a syntax error, such as: missing semicolon (unfortunately not necessarily can be checked out)
- During instantiation, examine the template code to see if all calls are valid, such as: The instantiation type does not support some function calls
Actual argument deduction
The process of determining template parameter types and values from function arguments is called template argument deduction. Arguments for multiple type parameters must match exactly.
As for such a function call:
Template <typename T1, TypeName T2, TypeName t3>void Fun (T1 t1, T2 T2, T3 T3) {//do something}int main () {fun (1, ' a ', 3.14); return 0;}
The compiler generates a function like this:
Where the type of the function parameter is exactly the same as the type passed by the calling function.
Type parameter conversions
Arguments are not typically converted to match an existing instantiation, but instead produce a new instance.
For a chestnut: Call the following function:
Template <typename t>t Add (t left, t right) {return left + right;} int Add (int left, int. right) {return left + right;} int main () {ADD (1.2, 3.4); return 0;}
That is, the program has already implemented the INT version of the Add function, then call Add (1.2, 3.4), the compiler will not implicitly convert 1.2 and 3.4 to int type, and then call the existing add version, but to re-synthesize a double version:
The premise, of course, is the ability to generate such a template function. If this template function cannot be generated, then only the existing version can be called.
The compiler performs only two conversions:
1. Const conversion: A function that receives a const reference or a const pointer can be called by a reference or a pointer to a non-const object, respectively
2. Array or function-to-pointer conversions: If the template parameter is not a reference type, the arguments to the type of the group or function are applied to the regular pointer conversions. An array real arguments as a pointer to its first element, and a function argument as a pointer to a function type.
The first type:
Template <typename t>t Add (const t &left,const t &right) {return left + right;} int main () {ADD (1.2, 3.4); return 0;}
In the face of such a pass, the compiler is able to complete the conversion of the 1.2 to const double & type because it is safe to do so.
The second type:
Template <typename t>int sum (T *t) {//do something}int main () {int arr[10];sum (arr); return 0;}
The array-to-pointer conversion is completed because the array itself is degraded when passed as a function argument, the parameter receives a pointer, and points to the first element of the array.
Template <typename t>int sum (T *t) {//do something}void fun () {//do something}int main () {sum (fun); return 0;}
The previous example completes the conversion of a function to a function pointer.
Template parameters
Function templates have two types of parameters: template parameters and call parameters. Template parameters are divided into template type and non-template type parameter.
Template parameter names can be used only after template parameters to the end of a template declaration or definition, following the name masking rule.
The name of the template parameter can only be used once in the same template parameter list.
All template parameters must precede the class or typename keyword decoration.
Note: You cannot specify a default template argument inside a function template.
Template type parameters are constants defined inside the template, and non-template type arguments can be used when constant expressions are required. For example:
Template <typename T, int size>//size is a non-template type parameter void sum (T (&arr) [size]) {}int main () {int arr[10];sum (arr); When called here, the 10 is automatically passed to size, as the number of array elements return 0;}
template parameter Description:
- Template formal parameter list use <> Surround
- As with the function parameter table, it must be separated by commas with multiple arguments, and the type can be the same or different
- Template parameter list cannot be empty
- A template parameter can be a type parameter, or it can be a non-type new parameter, followed by a type parameter after class and TypeName
- The template type parameter can be used as a type description trailing characters anywhere in the template, using the same methods as built-in or custom types to specify function parameter types, return values, local variables, and coercion type conversions
- In the template parameter list, class and TypeName have the same meaning, can be interchanged, and use typename more intuitively. However, the keyword TypeName is added to C + + as a C + + standard, which may not be supported by the old compiler.
template function overloading
int Max (const int& left, const int & right) { return left>right? Left:right;} Template<typename t>t Max (const t& left, const t& right) {return left>right? Left:right;} Template<typename t>t Max (const t& A, const t& B, const t& c) { return Max (Max (A, B), c);}; int main () { Max (ten, +); Max<> (10, 20); 3. Generate with a template instead of invoking the same version of the display definition Max (ten); Max (ten, 20.12); Max<int> (10.0, 20.0); Displays the type Max (10.0, 20.0) that tells the compiler T; return 0;}
Description
- A non-template function can exist with a function template of the same name, and the function template can also be instantiated as a non-template function
- For non-template functions and function templates with the same name, if the other conditions are the same, the non-template function will be transferred at first, without generating an instance from the template. If a template can produce a function with a better match, the template is selected
- Explicitly specify an empty template argument list that tells the compiler that only templates can match this call, and that all template parameters should be deduced from the arguments
- The template function does not allow automatic type conversions, but ordinary functions can do automatic type conversions
The above function template cannot be used to compare two strings, and if the pass parameter is a string, the return is a comparison of two parameter addresses, not the result we want. So, there is the template function of the Special:
The template functions are in the following form:
1. Keyword template followed by an empty pair of angle brackets <>
2, followed by the template name and a pair of angle brackets, the angle brackets specify the template parameter of this special definition
3. Function formal parameter list
4. Function body
In a template-specific version of a call, the argument type must exactly match the formal parameter type of the special version function, and if it does not, the compiler instantiates an instance for the argument template definition.
Lift a chestnut:
Template <typename t>int cmp (const t&left, const T &right) {return left-right;} Template <>int cmp<const char * &> (const char * &p1, const char * &p2) {return strcmp (P1, p2);} int main () {const char *S1 = "abc"; const char *S2 = "ABD"; CMP (s1, S2); return 0;}
Again, the argument type must be the formal parameter type of the special version function.
Exact Match, even if there is no const in the front of the argument, and the template parameter does not constitute a special. The special version is written for this template, and the parameter type of the special version must be exactly the same as the template parameters, as in the above example, const &.
Class template
Format
Template<class parameter name 1, class parameter Name 2, ... class parameter name n>
Class name
{ ... };
Give me a chestnut:
Implement dynamic sequential table Template<typename T>class seqlist{public:seqlist (), seqlist ();p rivate:int _size; int _capacity; T* _data;}; Template <typename t>seqlist <t>:: Seqlist (): _size (0), _capacity (+), _data (new t[_capacity]) {}template & Lt;typename t>seqlist <t>::~ seqlist () {delete [] _data;} void Test1 () {seqlist<int > SL1; Seqlist<double > SL2;}
In contrast to calling a function template, when you use a class template, you must explicitly specify an argument for the template parameter!
Instantiation of a template class
As long as there is a different type, the compiler instantiates a corresponding class.
Seqlist<int > SL1;
seqlist<double > SL2;
When defining these two types of sequential tables, the compiler uses int and double instead of the template parameters, rewriting the Seqlist class, and finally creating a class named Seqlist<int> and Seqlist<double>.