Function type in C++ (1): function pointer

How to pass a function in C++, such as as a parameter of a class or other function.
There are types that need to represent functions, and there are a few different ways.
Originally, I wanted to summarize all the function types. After finishing the function pointers, there are a lot of bits and pieces, so let’s divide them into several articles.

function pointer

The method inherited from the C language is the most basic and essential way to represent the function type.
A function is some consecutive instructions. After the program is loaded into the memory, a memory address essentially represents the function entry.
When the program is running, the function is called, and after the parameter stack and registers are prepared, it jumps to the function entry address and starts to execute the corresponding logic.
After the execution is complete, clean up the stack, save the data, and return to the caller.

Compared with other methods, function pointer type definition is not very intuitive. The advantage is that it does not depend on existing functions (refer to the centralized definition method below), the most direct definition method.
It is slightly less readable for humans and more straightforward for compilers.

sample code

For the sample code above, see the instructions below:

// 一个例子函数
int func(int a) {
	return a+1;
}

typedef int (*func_type) (int); // typedef定义函数指针类型
using func_type_other = int (*) (int);  // using定义指针类型语法

func_type ptr2 = func; // 给函数指针赋值,指向具体函数,函数名本身就是指针
func_type ptr3 = &func; // 给函数指针赋值,指向具体函数,对函数名去地址操作,效果等同直接用函数名

cout << ptr2(1); // 输出2
cout << ptr3(2); // 输出3

// 函数指针作为参数使用
void call_func(func_type one_func) {
	cout << "call_func: " << one_func(5) << endl; // 输出 6
}

call_func(func); // 直接传入函数名
call_func(ptr2); // 传入函数指针

Basic steps to define function pointers (definition method 1)

1) First write a function prototype declaration, the above example is:
int func(int a);
2) Enclose the function name in parentheses, then replace the function name with "*type name", and keep the others unchanged.
For input parameters, only the type is provided, and the parameter name is optional.
int (*func_type) (int a);
3) Add typedef in front:
typedef int (*func_type) (int a);

大功告成,func_type就是要定义的函数指针类型,可以定义函数指针的变量或参数。

illustrate

a) In the typedef declaration, the asterisk * in front of the type is required, and only the pointer type can match the address type represented by the function name.
b) The function name (func) and the address operation (&func) for the function name are equivalent.
c) In the definition of steps, 1) and 2) are in order, and 3) can be placed anywhere.

Declare a function pointer with decltype (definition method 2)

By using the new decltype of C++, the function pointer definition can be simplified, provided that there is a function of the same type.
If you are developing a function library, if you define an interface type without a function, you can only use the above method to define it.

// 例子函数
int func(int a) {
	return a+1;
}

typedef decltype(func) *func_type_two;
using func_type_thress = decltype(func)*; // 注意末尾星号*,func_type_thress和func_type_two完全等价,只是新旧语法差异

func_type_two ptr4 = func;
// func_type_thress ptr4 = func;
cout << ptr4(6);

// 函数指针作为参数使用
void call_func(func_type one_func) {
	cout << "call_func: " << one_func(5) << endl; // 输出 6
}
call_func(ptr4); // 可以调用,说明不同方式定义的函数指针类型相同

illustrate

a) The asterisk * in front of the type is required and used in the same way as before.
b) Pass ptr4 to call_func to check that the function pointer types defined in different ways are the same.
In fact, as long as the function name can be assigned to the function pointer, it means that it is the same type.

Declare function pointers with ultimate kill auto (definition method 3)

If you can't figure it out, use auto to cover the bottom. Again, an existing reference function is required. Not suitable for directly defining parameter types.
Suitable for storing or passing a function pointer during code processing.
It is easy to write, but not very readable for those who are not familiar with the logic of the code.

// 例子函数
int func(int a) {
	return a+1;
}

auto *ptr5 = func;
auto ptr6 = func;
auto ptr7 = &func; // ptr5, ptr6, ptr7都是同样类型的函数指针

auto &ptr8 = func; // ptr8是函数的引用,编译器内部处理函数引用和指针一样,通过下面的调用可以验证
ptr8(8);
call_func(ptr8);

Function reference, the effect is equivalent to a function pointer (definition method 4)

// 例子函数
int func(int a) {
	return a+1;
}

auto &ptr8 = func; // ptr8是函数的引用,编译器内部处理函数引用和指针一样,通过下面的调用可以验证
ptr8(8);
call_func(ptr8);

using defines the template type pointer

This ability cannot be realized with typedef, but it is a basic ability in the template library. The using syntax should be preferred.

template <typename T>
using Compare = bool (*) (T&, T&);

template <typename T>
void sort(vector<T> vec, Compare<T> compare);

Summarize

Subsequent additions of various "syntactic sugar" simplifies the definition method, and the most basic definition method is essentially the same.
The key is to understand the essence of the pointer pointing to the function entry address, and the others are just to assist the compiler to identify the type of function pointer, including input and output types.

Guess you like

Origin blog.csdn.net/yinminsumeng/article/details/129232645