Advanced Series Navigation from C to C++
1. Function template
The concept of function template is proposed in C++. Function templates can be seen as macros with type checking and can be adapted to any data type. This is also the idea of generic programming, which does not consider the specific data type of programming, the specific data type is determined by the caller.
Function templates are defined as follows:
template <typename T> Type Funname(T x) { ... }
The template tells the compiler the following definition of the template and tells the compiler T to be a generic type.
- Experiment:
template <typename T> T add(T num_A, T num_B) { return num_A + num_B; } int main() { int iSum = add<int>(1, 2); cout << "iSum = " << iSum << endl; // iSum = 3 float fSum = add<float>(0.3, 0.5); cout << "fSum = " << fSum << endl; // fSum = 0.8 string strSum = add<string>("123", "456"); cout << "strSum = " << "\"" << strSum << "\"" << endl; // strSum = "123456" return 0; }
2. Function Modular Version Quality
The essence of function templates is the replacement of data types. For function templates, the compiler compiles them twice. The first is the compilation of the function template itself, and the second is the compilation of the function after data type replacement when the function is called. Therefore, each function call will produce a new function copy, which will undoubtedly reduce the compilation efficiency of the program, but the use of template technology can greatly improve the programming efficiency, so it is worth sacrificing the lower compilation efficiency for higher programming efficiency.
It should be noted that the function template itself does not allow implicit type conversion, that is, when automatically deducing the type, strict matching must be made; when the display type is specified, that is, when compiled twice, implicit type conversion can be carried out.
- Experiment:
typedef int(iFun)(int,int); typedef float(fFun)(float,float); template <typename T> T add(T num_A, T num_B) { return num_A - num_B; } int main() { int iSum = add<int>(1, 2); cout << "iSum = " << iSum << endl; // iSum = -1 iFun* pi = add<int>; cout << "pi = " << reinterpret_cast<void*>(pi) << endl; // pi = 0x400a80 float fSum = add<float>(0.3, 0.5); cout << "fSum = " << fSum << endl; // fSum = -0.2 fFun* pf = add<float>; cout << "pf = " << reinterpret_cast<void*>(pf) << endl; // pf = 0x400a92 // string strSum = add<string>("123", "456"); // error: no match for 'operator-' (operand types are 'std::__cxx11::basic_string<char>' and 'std::__cxx11::basic_string<char>') return 0; }
In the above experiments, compilation errors occur when using only string type templates, because subtraction is used in template functions and string type has no subtraction related function implementation, so compilation errors occur during secondary compilation. The other data types of function templates do not have compilation errors, and the function addresses invoked are different, which also proves that the template will be compiled twice.
3. Multi-parameter function template
Function templates support multiple generic parameters, specifying type parameters from left to right. If no data type is specified, the data type of the argument shall prevail. Because the return type of function can not be deduced automatically, the return type is taken as the first type parameter in engineering.
- Experiment:
template <typename T1, typename T2, typename T3> T1 add(T2 num_A, T3 num_B) { return static_cast<T1>(num_A + num_B); } int main() { int iSum = add<int, float, float>(1.1, 2.2); cout << "iSum = " << iSum << endl; // iSum = 3 float fSum = add<float, int>(1, 2.2); // Equivalent to add < float, int, float > (1, 2.2) cout << "fSum = " << fSum << endl; // fSum = 3.2 iSum = add<int>(1.1, 2.2); // Equivalent to add < int, float, float > (1.1, 2.2) cout << "iSum = " << iSum << endl; // iSum = 3 return 0; }
4. Function overload and function template
Because function templates can be deduced automatically, it is possible that both function overload and function template can be satisfied when calling a function. In this case, the compiler will call the overloaded function first. If you want to specify the calling function template, you can use "<>" at the function call to express the qualified calling function template.
- Experiment:
template <typename T> void Print(T num) { cout << "void Print(T num): " << num << endl; } void Print(int num) { cout << "void Print(int num): " << num << endl; } int main() { Print(100); // void Print(int num): 100 Print<>(100); // void Print(T num): 100 Print(3.14); // void Print(T num): 3.14 return 0; }