Chapter VIII Function exploration
1. C + + inline function
After the function is created normally, when the program calls the function, the program jumps to the function address. When using inline functions, the compiler will directly replace the function call with the function code during compilation, which saves the time for the program to jump to the function address and speeds up the running speed. However, each time an inline function is called, a copy of the function will be created, and ten copies will be created ten times. Therefore, to create inline functions, the number of lines of code should not be large, and inline functions cannot be recursive. When using inline functions, the keyword inline should be added before the function declaration and definition. Compared with macro definition, inline function can better achieve the purpose of passing parameters by value.
inline double squar(double x) { return x * x; } // Inline function #Define square (x) x * x / / macro int a = aquar(3+2); // a = 5 * 5 = 25 int b = SAUAR(3+2); // b = 3 + 2 * 3 + 2 = 11
2. Reference variables
A reference is equivalent to aliasing a variable. Both the reference and the original variable name refer to the same variable. References are defined as:
int rats; int & rodents = rats; // rodents is a reference to rats, & not an address character, but a reference to int
References must be initialized at the time of declaration. They cannot be declared before assignment, just as const constants are declared.
In C + +, the important role of reference is as a function parameter. Reference as a parameter can change the original variable (alias the original variable, and the function directly operates on the original variable). The function call initializes the formal parameter with the actual parameter:
void swapr(int & a, int & b);
To understand a reference, you can think of it as a pointer and directly modify the original data in memory.
Reference is an alias of a variable. Therefore, the parameter requirements of a function whose formal parameter is a reference are more stringent than those of a function whose formal parameter is a general variable:
int cube(int a); int recube(int &b); int x = 2; int m = cube(x + 2); // legitimate int z1 = cube(4.13); // legitimate int n = recube(x + 2); // wrongful int z1 = recube(4.13); // wrongful
When the formal parameter is a reference to const,
int con_recube(const int& c); int num1 = con_recube(x + 2); // legitimate int num2 = con_recube(4.13); // legitimate
The type of the function argument is correct, but it is not an lvalue; Or the type does not match the formal parameter, but can be converted to a matching type. The function will create a temporary variable and initialize it to the value of the type corresponding to the formal parameter. Then the function formal parameter is a reference to the temporary variable, and the temporary variable will be released after the function call. When a formal parameter is a pointer, it has the same effect as a reference. That is to say, if the intention of a function that accepts a reference or pointer is to modify parameters, it will be organized when creating temporary variables. If the parameters are limited by const, it will eliminate this side effect and create temporary variables without modifying formal parameters.
3. Default parameters
When defining a default parameter, you can only add a default value from right to left. When defining a function, you can omit the default value.
int harpo(int n, int m = 4, int j = 5); // legitimate int harpo(int n, int m, int j) // Omit default values when defining { ... } int chico(int n, int m = 6, int j); // illegal
You cannot skip parameters when calling a default function
int beeps = harpo(3, , 8) // illegal
4. Function overloading
Function overloading is only related to the characteristics of parameters, that is, the number, type or order of parameters, and has nothing to do with the return value of the function.
When calling overloaded functions, if there is no function that exactly matches the arguments, standard type cast will be used. If multiple overloads can be cast, an error will be reported when matching. References are not overloaded, but const.
void dribble(const char*) void dribble(char*) // heavy load
When the parameters of an overloaded function are lvalues, const s, and rvalues, the most matching function will be called.
void stove(double & r1); void stove(const double & r2); void stove(double && r3); double x = 55.3; const double y = 32.2; stove(x); // Call void stop (double & R1) stove(y); // Call void stop (const double & R2) stove(x+y); // Call void stop (double && R3)
5. Function template
Format of function template:
template <typename T> // typename can be replaced by class void Swap(T & a, T & b); // Function declaration ... template <typename T> void Swap(T & a, T & b) // Function definition { T temp; temp = a; a = b; b = temp; }
T indicates any standard type. The keywords template, typename and angle brackets cannot be omitted. They must be included in the declaration and definition. The function template automatically generates the corresponding function definition every time the template function is called, which does not shorten the program.
Function templates can also be overloaded, and the formal parameters of overloaded functions can also have other types, not only T type.
template <typename T> void Swap(T a[], T b[], int n);
For types that are not applicable in the template function definition, for example, in a = b, T is an array, or if (a > b), and T is a structure. Display materialization can be used to deal with this problem.
struct job { ... }; template <> void Swap<job>(job &, job &); // The function template shows the materialized prototype, and there are no parameters in the first angle bracket ... // The < job > of swap < job > is optional template <> void Swap<job>(job &, job &) // Function definition { ... }
The compiler uses the function definition generated by the template, that is, the template instance, which is called implicit instantiation. c + + allows display instantiation. When calling template functions, the following methods are adopted:
Swap<int>(m, n); // Show instantiation, tell the compiler to generate a function definition where T is int, and // m. Cast the type of n to int
There are no angle brackets after the instantiated template, but there are when the materialized function declaration or definition is displayed. If you use the same type of display instantiation and display materialization in the same file, an error will be reported.
int m = 5; double x = 14.3; Swap<double>(m, x); // An error will be reported. M and X are non const references, and a copy will not be created. // A reference to m cannot be cast to double
If there are multiple matching prototypes such as overloads or templates, an error will be reported. The function matching the prototype has priority. If the argument is non const when the formal parameter is a pointer or reference, the function whose formal parameter is non const has priority over the function whose formal parameter is const. Non template functions take precedence over template functions. Explicit materialization takes precedence over implicit instantiation. For multiple matching functions, more specific functions will be selected.
When a function is called, angle brackets can be used to tell the compiler to use the template:
template <typename T> T lesser(T a, T b); int lesser(int a, int b); int main() { int m = 4; int n = 8; double x = 15.3; double y = 21.4; lesser(m, n); // Calling a non template function lesser(x, y); // Call template function lesser<>(m, n); // Display tells the compiler to use template functions lesser<int>(x, y) // Explicit Instantiation return 0; }
decltype keyword can infer variable types:
//decltype(exp) var; // Exp has no parentheses, and the type of var is the same as exp double x = 5.5; double y = 7.9; double & rx = x; const double *pd; decltype(x) w; // w is of type double decltype(rx) u = y; // rx is a double & type decltype(pd) v; // pd is of type const double * // exp is a function call, and the type of var is the same as the return type of the function long indeed(int); decltype (indeed(3)) m; // m is an int type and will not actually call the function. The compiler only looks at it // Function return type // Exp has parentheses, and the type of var is a reference to exp double xx = 4.4; decltype((xx)) r2 = xx; // The type of r2 is double& decltype(xx) w = xx; // The type of w is double
For the following cases:
template<class T1, class T2> decltype(x+y) gt(T1 x, T2 y); // The return type cannot be inferred this way
X and y are not declared, and the compiler cannot know what x and y are.
You can use the method of postposition of return type:
template <class T1, class T2> auto gt(T1 x, T2 y) -> decltype(x+y); // statement // definition template <class T1, class T2> auto gt(T1 x, T2 y) -> decltype(x+y) { ... }
In this way, decltype follows the declaration of parameter x and y.