如果C ++ FAQ Lite中的以下内容为真:“函数名称衰减为指向函数的指针”(因为数组名称衰减为指向其第一个元素的指针);为什么我们必须加入&符号?
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = &Fred::f;
而不只是:
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = Fred::f;
在第二种情况下,Fred :: f是一个函数,可以衰减到指向该函数的指针。
我希望这个问题不是那么愚蠢。
答案 0 :(得分:17)
原始答案:
因为成员函数不是函数而成员函数指针不是函数指针。因此,衰变规则不适用。
此外,C ++中有函数类型,但不是成员函数类型。因此,您可以在需要指向函数的位置使用函数,但是您不能使用成员函数,因为没有这样的东西,只有指向成员函数的指针。你的例子中的f是一个函数。另一方面,Fred :: f是......好吧,没什么。
另外,我认为“函数的名称可以衰减......”。不,名称不能做任何事情,函数类型的左值可以隐式转换为指向函数的指针,就重载解析而言,这是一个身份转换
编辑以澄清我的回答:
C ++中的每个表达式都有一个类型和值。偶尔可以将一种类型的值转换为另一种类型的值。对这些转换进行排序,以使一次转换更好,另一次转换主要用于函数重载解析。
其中一种转换类型称为左值到右值转换。当左值出现在需要右值的上下文中时,将发生此转换。通常这种转换什么都不做,例如:
int i = 4, j = 5;
i = j;
第二行上的是一个左值,但这里需要一个右值,因此j被转换为右值。但这不是一个可观察到的转换,是吗?但是有些情况下可以观察到左值到右值的转换。也就是说, n T数组的左值可以转换为T*
类型的右值,其值是数组的第一个元素的地址 和 类型为“具有签名S的函数”的左值“类型为”具有签名S的函数的指针“的右值,其值为函数的地址
这意味着当我们将函数赋值给函数指针时,函数lvalue会隐式转换为它的地址。
void f() {}
void (*p) () = f; //f is converted to rvalue
f是一个表达式并且有一个类型。 f的类型是void()
C ++中没有member-function
这样的类型
有指向成员函数的指针,但不是成员函数本身。我当然在谈论非静态功能。静态函数的工作方式与普通函数相同,也就是说,您不必编写&X::f
,而是可以编写X::f
为什么?因为X :: f具有类型函数并且发生上述转换。但是,如果f是非静态的,那么X :: f的类型是什么?哦,是的,它没有类型,因此不是表达式,因此没有值,因此该值不能转换为任何值。
引用标准:5.3.1第3条 指向成员的指针仅在显式&使用它的操作数是一个未括在括号中的限定id。 [注意:也就是说,表达式&(qualified-id),其中qualified-id括在括号中,不形成“指向成员的指针”类型的表达式。也不是qualified-id,因为没有隐含从非静态成员函数的qualified-id转换为“指向成员函数的指针”类型,因为从函数类型的左值到类型“指向函数的指针”(4.3)。也不是& nonqualified-id指向成员的指针,即使在范围内也是如此 unqualified-id的类。 ]
希望这更清楚......