Как объявить указатель на функцию в C++

Ответ

В C++ есть несколько способов объявить указатель на функцию.

1. Классический C-стиль:

// Указатель на функцию, принимающую int и const char*, возвращающую void
void (*printFunc)(int, const char*);

// Пример использования
void printMessage(int id, const char* msg) {
    std::cout << "[" << id << "] " << msg << std::endl;
}

int main() {
    printFunc = &printMessage; // Присваивание адреса функции
    printFunc(1, "Hello");     // Вызов через указатель
}

2. Псевдоним типа для удобства (typedef/using):

// С typedef (унаследовано из C)
typedef void (*PrintCallback)(int, const char*);
PrintCallback callback = printMessage;

// С using (предпочтительный современный способ C++)
using PrintHandler = void (*)(int, const char*);
PrintHandler handler = printMessage;

3. Современный C++ с std::function (более гибко):

#include <functional>
#include <iostream>

// std::function может хранить любой вызываемый объект
std::function<void(int, const char*)> funcObj;

funcObj = printMessage;          // Указатель на функцию
funcObj = [](int id, const char* msg) { // Лямбда-выражение
    std::cerr << "Error " << id << ": " << msg << 'n';
};

// Вызов одинаков для всех типов
funcObj(42, "Test");

Ключевые отличия:

  • Указатель в стиле C — легковесный, но не может хранить лямбды с захватом или функциональные объекты.
  • std::function — универсальная обертка с небольшим оверхедом, подходит для большинства случаев в современном C++.

Ответ 18+ 🔞

Э, слушай, тут тема про указатели на функции в C++. Ну, ёпта, смотри, как будто на дворе 2002-й год, но до сих пор актуально, хоть и выглядит местами как манда с ушами.

Вот, блядь, классический C-стиль, от которого глаза на лоб лезут. Выглядит как хуй в пальто, но работает.

void (*printFunc)(int, const char*);

Смотри на эту хуйню: void (*printFunc). Это, блядь, указатель на функцию, которая принимает int и const char*, а сама нихуя не возвращает. Объявляешь, присваиваешь адрес функции — и поехали. Просто, но синтаксис — терпения ноль ебать, пока запомнишь, где звёздочку ставить.

Дальше идёт спасение для мозгов — псевдонимы. Раньше через typedef мучались, это как ебать копать лопатой. Сейчас, слава богу, есть using.

using PrintHandler = void (*)(int, const char*);

Вот это уже похоже на правду. Объявил один раз PrintHandler и юзаешь, где надо. Не нужно каждый раз этот ужас void (*)() писать, а то волнение ебать начинается.

А теперь, блядь, современная магия — std::function. Это уже не просто указатель, а, можно сказать, универсальная принималка всего, что можно вызвать. Лямбду с захватом? Запросто. Функтор? Без проблем. Обычную функцию? Да похуй, тоже влезет.

std::function<void(int, const char*)> funcObj;
funcObj = printMessage; // Старую функцию
funcObj = [](int id, const char* msg) { ... }; // Новую лямбду

Выглядит чисто и понятно. Правда, под капотом у него овердохуища всякой умной логики, так что если тебе на микросекунды считать — может, и не лучший выбор. Но для 99% случаев — то, что надо.

Короче, резюме:

  • C-указатель — быстрый и голый, но с ним как с хитрой жопой — не угадаешь, когда ошибёшься в синтаксисе. Для лямбд с захватом — ни хуя себе, не подойдёт.
  • std::function — жирненький, универсальный, всех поимеет. Идеально, когда нужна гибкость и не нужно выжимать каждую каплю производительности. Главное — не выёбывайся и используй его, где можно.