Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member function pointer

Tags:

If the following from the C++ FAQ Lite is true: "a function name decays to a pointer to the function" (as an array name decays to a pointer to its first element); why do we have to include the ampersand?

typedef  int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = &Fred::f;

And not just:

typedef  int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = Fred::f;

In the second case Fred::f is a function and can decay to a pointer to that function.

I hope this question is not that stupid.

like image 499
Cedric H. Avatar asked Oct 24 '10 14:10

Cedric H.


1 Answers

Original answer:

because a member-function is not a function and a member-function-pointer is not a function-pointer. Therefore the rules of decay don't apply.

Also, there is function type in C++, but not member-function type. So you can use a function in places where a pointer-to-function is expected, but you can't use a member-function because there is no such thing, only pointer-to-member-function. f in your example is a function. On the other hand, Fred::f is... well, nothing.

Also, I would argue that "the name of a function can decay...". No, the name cannot do anything, an lvalue of function type can be implicitly converted to a pointer-to-function, and this is an identity conversion as far as overload resolution is concerned

Editing to clarify my answer:

Every expression in C++ has a type and value. A value of one type can occasionally be converted to a value of another type. These conversions are ranked so that to make one conversion better than another one mainly for function overload resolution.

One of the types of the conversions is called lvalue-to-rvalue conversion. When an lvalue appears in a context where an rvalue is required this conversion takes place. Usually this kind of conversion does nothing, for example:

int i = 4, j = 5;
i = j;

on the second line j is an lvalue, but an rvalue is needed here, so j is converted to an rvalue. But this is not an observable conversion, is it? But there are cases where the lvalue-to-rvalue conversion can be observed. That is, an lvalue of array of n T can be converted to an rvalue of type T* whose value is the address of the first element of the array and an lvalue of type "function with signature S" an rvalue of type "pointer to function with signature S" whose value is the function's address

That means that when we assign a function to a pointer-to-function the function lvalue is implicitly converted to its address.

void f() {}
void (*p) () = f; //f is converted to rvalue

f is an expression and has a type. f's type is void()

There is no such type in C++ as a member-function There are pointers-to-member-functions, but not member functions themselves. I am talking of course about nonstatic functions. Static functions work the same way as ordinary functions, that is, you don't have to write &X::f, instead you can write X::f Why? Because X::f has a type function and the abovementioned conversion takes place. If f is nonstatic, however, X::f is of type... what? Oh yeah, it doesn't have a type and therefore is not an expression and therefore doesn't have value and therefore that value cannot be converted to anything.

Quote from the standard: 5.3.1 clause 3 A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because there is no implicit conversion from a qualified-id for a nonstatic member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is &unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. ]

Hope this was clearer...

like image 80
Armen Tsirunyan Avatar answered Sep 28 '22 05:09

Armen Tsirunyan