Указатель на функцию-член - PullRequest
16 голосов
/ 24 октября 2010

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

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

1 Ответ

17 голосов
/ 24 октября 2010

Исходный ответ:

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

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

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

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

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

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

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

во второй строке j является lvalue, но здесь необходимо r-значение, поэтому j преобразуется в r-значение.Но это не наблюдаемое преобразование, не так ли?Но есть случаи, когда можно наблюдать преобразование lvalue в rvalue.То есть значение массива 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 Aуказатель на член формируется только тогда, когда используется явное &, а его операндом является квалифицированный идентификатор, не заключенный в скобки.[Примечание: то есть выражение & (квалифицированный идентификатор), где квалифицированный идентификатор заключен в круглые скобки, не образует выражение типа «указатель на член». Также не используется квалифицированный идентификатор, поскольку не существует неявного преобразованияот квалифицированного идентификатора для нестатической функции-члена к типу «указатель на функцию-член», поскольку существует от lvalue типа функции до типа «указатель на функцию» (4.3).И & unqualified-id также не является указателем на член, даже в пределах класса unqualified-id.]

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

...