Implicit conversion from function to pointer, special for non-static member functions

Reprinted from: https://www.cnblogs.com/Esfog/archive/2012/04/23/2467249.html
https://blog.csdn.net/weixin_34194702/article/details/92488498
https://zh.cppreference .com/w/cpp/language/implicit_conversion
https://www.zhihu.com/question/277360626

Allocation of functions in memory

       First of all, when C/C++ creates a variable such as int a, a 4-byte (may vary depending on the machine) space will be allocated in the memory to store the int variable. Assume that the 4-byte The starting address is 0XFF0A, so there is actually a mapping between variable names and memory addresses . That is, a can be regarded as an identifier. It only represents the address 0XFF0A. In the program, the operation you perform on a actually also It is an operation on the 4 bytes of the address starting with 0XFF0A in the memory . Especially if the address operation is performed on a, that is, &a actually returns the address value 0XFF0A. In fact, you can see that the result is returning a pointer to this address. Pointers (if you don’t understand, just pretend I didn’t say it). In the same way, for the functions we create in the program, they are stored in a separate area in the program, and when we call them, we need an address to point to it uniquely, just like using variables, so each function needs an address to uniquely point to it. Identify yourself (that is, what we often call the entry address), just like the a above corresponds to 0XFF0A, then suppose we define an int fun(int){}, the entry address of the function is 0XAAEE, then fun is the function name. Mapping 0XAAEE, just like the int variable a above, if you take the address & fun on it, it will return 0XAAEE. In fact, fun is also a type, just treat it as a function name type. Just remember that the function name itself is not a Pointer types are fine.

Function call (function is implicitly converted to function pointer)

  Let’s talk about the key points below. We all know that when calling a function, it is enough to have a function name, such as fun(2). Don’t think that you can call the function as long as you have a function name . In fact, this is just a confusing point in the writing method, and the compiler The so-called "Function-to-pointer conversion" is always performed during compilation , which means that the function name is implicitly converted into a function pointer type , that is, the function is called through the function pointer , so if you write the function when calling the function as (&fun)(2) also works, because &fun actually returns a function pointer, refer to the example of &a in the previous paragraph, but this way of writing is very uncommon, even if you do not explicitly write &, the compiler It will also be converted implicitly. Note that there must be brackets around &fun. This is because of the operator precedence issue. In fact, even if you write it as (*fun)(2) , it will still run normally. This is because when the compiler sees fun, it finds that there is no & in front of it, that is, if you do not explicitly convert it to a pointer, then it must implicitly convert it to a pointer. is converted into a pointer. After the conversion is completed, it is found that there is another * in front of it. At this time, the so-called "dereference" operation is performed, that is, the value is taken out from the pointer behind the *, and the value is actually 0XAAEE is the function name fun. Such an implicit conversion and then a dereference are actually equivalent to doing nothing, so the system will perform another implicit "Function-to-pointer conversion", even if you write ( * ******fun)(2) will also run normally. It's the same as the previous one. It just requires a few more repeated translation operations. It's all done by the compiler itself, so don't worry about it!

void foo()
{
	cout << "foo" << endl;
}

int main()
{
	cout << foo << "-" << *foo << "-" << &foo << "-" << ****foo << endl;
	foo();
	(&foo)();
	(*foo)();
	(**************foo)();
	void(*p)() = foo;
	void(*p1)() = *foo;
	void(*p2)() = &foo;
	p();
	p1();
	p2();
	(*p)();
	(*****p)();
	//(&p)();  //&p为存放这个函数指针的指针不能这样使用
}

Special features of non-static member functions (cannot be implicitly converted and need to add &)

    There is such a sentence in the implicit conversion of cppreference.com , function to pointer: an lvalue  of a function type  Tcan be implicitly converted into a pure rvalue of a pointer to the function . This does not apply to non-static member functions because there is no lvalue that refers to a non-static member function . In C, strictly speaking, the conversion from function to pointer is not an lvalue conversion, because the function in C is neither an lvalue nor an rvalue. For this reason, the clause content in C does not indicate the conversion. lvalue property. But for C++, functions are lvalues ​​(I don’t know yet why functions are lvalues?) , so the conversion is an lvalue conversion, and the result is an rvalue pointer.

    Regarding the lvalue nature of C++ functions, there is an exception, that is, non-static member functions are not lvalues . The author was initially very confused by this, because in abstract nature, there is nothing inconsistent with the meaning of C++ lvalue in non-static member functions. The author once sent an email to Dr. Bjarne Stroustrup, the founder of C++, to ask him about this issue. BS said in his reply that he thought this provision was an inelegant technical way to distinguish between ordinary functions and non-static functions. member functions. That is to say, this is a man-made rule. Since non-static member functions are excluded from the lvalue category, there is no conversion from function to pointer for non-static member functions. Non-static member function pointers must be obtained through the & operator . Therefore, when defining a non-static member function, you need to add &. This is why when we use the bind function, we need to add & if we are binding a member function within the class .

#include "pch.h"
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;

class A
{
public:
	void func()
	{
		cout << "func" << endl;
	}
};

int main()
{
	void (A::*p)() = &A::func;
	//void (A::*p1)() = A::func;  这样定义非法
	A* a = new A();
	auto n = bind(&A::func, _1);
	n(a);   //成功调用打印出func
	auto n2 = bind(&A::func, a);
	n2();	//成功调用打印出func

	auto n3 = bind(&A::func);   //bind的参数错误,参数的长度与原可调用对象的长度不一致,其后果未定义
}

It should be noted that func is a non-static member function inside the class. When it is called, a default this pointer will be passed in, so the number of its parameters during bind and the number of parameters when calling must match , otherwise an error will occur.

Guess you like

Origin blog.csdn.net/SwordArcher/article/details/113753476