Указатель функции участника

Если следующее из С++ 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 является функцией и может распадаться на указатель на эту функцию.

Надеюсь, этот вопрос не такой глупый.

Ответы

Ответ 1

Оригинальный ответ:

потому что функция-член не является функцией, а указатель-функция-функция не является указателем на функцию. Поэтому правила распада не применяются.

Кроме того, существует тип функции в С++, но не тип член-функции. Таким образом, вы можете использовать функцию в тех местах, где ожидается от указателя к функции, но вы не можете использовать функцию-член, потому что нет такой вещи, только функция-указатель-член. f в вашем примере - это функция. С другой стороны, Fred:: f... ну, ничего.

Кроме того, я бы сказал, что "имя функции может распадаться...". Нет, имя ничего не может сделать, lvalue типа функции может быть неявно преобразовано в указатель-к-функции, и это преобразование идентичности в отношении разрешения перегрузки

Редактирование, чтобы уточнить мой ответ:

Каждое выражение в С++ имеет тип и значение. Значение одного типа иногда может быть преобразовано в значение другого типа. Эти преобразования оцениваются так, чтобы сделать одно преобразование лучше, чем другое, в основном для разрешения функции перегрузки.

Один из типов преобразований называется преобразованием lvalue-to-rvalue. Когда lvalue появляется в контексте, где требуется rvalue, это преобразование имеет место. Обычно такой вид преобразования ничего не делает, например:

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

на второй строке j является lvalue, но здесь требуется r значение, поэтому j преобразуется в r-значение. Но это не наблюдаемое обращение, не так ли? Но бывают случаи, когда можно наблюдать преобразование lvalue-to-rvalue. То есть lvalue массива n T может быть преобразовано в rvalue типа T*, значение которого является адресом первого элемента массива и функции lvalue type "с сигнатурой S" rvalue типа "указатель на функцию с сигнатурой S", значением которой является адрес функции

Это означает, что когда мы назначаем функцию указателю на функцию, функция lvalue неявно преобразуется в адрес.

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

f является выражением и имеет тип. f type void()

В С++ такого типа нет, как member-function Существуют указатели-на-члены-функции, но не сами функции-члены. Я говорю, конечно, о нестатических функциях. Статические функции работают так же, как обычные функции, т.е. Вам не нужно писать &X::f, вместо этого вы можете написать X::f Зачем? Поскольку X:: f имеет функцию типа и имеет место вышеупомянутое преобразование. Если f нестатически, X:: f имеет тип... что? О да, у него нет типа и, следовательно, не является выражением и поэтому не имеет значения, и поэтому это значение не может быть преобразовано ни в что.

Цитата из стандарта: 5.3.1 пункт 3 Указатель на член формируется только тогда, когда явный и используется, а его операнд - это идентификатор, не заключенный в круглые скобки. [Примечание: то есть выражение & (qualified-id), где идентификатор с квалификацией заключен в круглые скобки, не образует выражение типа "указатель на элемент". Также не имеет идентификатор-идентификатор, потому что нет никакого неявного преобразования из квалифицированного идентификатора для нестатической функции-члена в тип "указатель на функцию-член", поскольку от lvalue типа функции от типа "указатель на функцию" (4.3)). Не является & unqualified-id указателем на члена, даже в рамках неквалифицированный класс. ]

Надеюсь, что это было яснее...