#c #templates #gcc
#c #функции-указатели
Вопрос:
Я пытаюсь провести некоторое тестирование с помощью указателя на функцию-член. Что не так с этим кодом? bigCat.*pcat();
Инструкция не компилируется.
class cat {
public:
void walk() {
printf("cat is walking n");
}
};
int main(){
cat bigCat;
void (cat::*pcat)();
pcat = amp;cat::walk;
bigCat.*pcat();
}
Ответ №1:
Требуется больше круглых скобок:
(bigCat.*pcat)();
^ ^
Вызов функции ( ()
) имеет более высокий приоритет, чем оператор привязки указателя к члену ( .*
). Унарные операторы имеют более высокий приоритет, чем бинарные операторы.
Комментарии:
1. @AdrianCornish: Нет, но
pcat
не называет член, он называет указатель на член, объявленный как локальная переменная вmain
.2. Я думаю, это немного похоже на вызов виртуальной функции — Есть ли хороший вариант использования / проблема, для которой это полезно — изо всех сил пытаюсь придумать, как использовать это для хорошего кода
3. @AdrianCornish: я никогда не использовал эту функцию и не видел, чтобы она использовалась в коде, написанном другими. Наверняка кто-то его использовал… но вариантов использования немного, и они далеко друг от друга.
4. @AdrianCornish: Это редко используемая функция. Я часто использовал его в общем коде, например, у меня был набор
for_each
алгоритмов, подобных алгоритмам, которые принимали последовательность указателей и вызывали функцию-член для каждого из объектов, на которые указывали. Это избавило меня от необходимости использовать уродливые заклинания для связывания функций. Это было до того, как лямбда-выражения сделали это намного проще… если бы мне пришлось переписать весь этот код, я бы, вероятно, использовал лямбды для большинства применений.5. Я обнаружил, что использую его при рефакторинге, и я вижу одну и ту же логику до и после вызова функции-члена, повторяемого снова и снова. Это может быть преобразовано в функцию, которая принимает указатель на функцию-член для вызова, поэтому логика до и после может быть записана только один раз.
Ответ №2:
Сегодня каноническим способом является использование шаблона функции std::invoke, особенно в общем коде. Пожалуйста, обратите внимание, что указатель на функцию-член идет первым:
import <functional>;
std::invoke(pcat, bigCat);
Что вы получаете: унифицированный синтаксис вызова практически для всего, что можно вызвать.
Накладные расходы: отсутствуют.
Комментарии:
1. Предостережение: требуется C 17 (конечно, все меньше проблем)