TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #720 4.86K
std::invoke
#опытным

Если вы хотите универсально работать с любыми коллбэками в вашем коде, то вам просто необходимо знать эту функцию и уметь с ней работать. Это единственный способ в С++ вызвать любую сущность, походящую на функцию.

Давайте посмотрим на пример:

template <typename Callback, typename... Args>
void process_and_call(Callback&& callback, Args&&... args) {
// some processing
std::forward<Callback>(callback)(std::forward<Args>(args)...);
}


Все просто: передаем шаблонный коллбэк и его аргументы и используем perfect forwarding для вызова коллбэка.

Есть ли проблема в этом коде? Задумайтесь на секунду.

И проблема есть!

Что если мы попробуем передать в process_and_call указатель на нестатический метод класса? Метод класса - это такая же функция, просто она принимает неявный параметр this. В С++ есть специальный синтаксис для вызова методов классов:

class Data {
public:
void memberFunction(int value) {
std::cout << "Data::memberFunction called with value: " << value << "\n";
}
};

Data data;

// Создаем указатель на метод класса
auto methodPtr = &Data::memberFunction;

// Вызываем метод через указатель на объекте
(data.*methodPtr)(42);


Согласитесь, что этот синтаксис отличается от std::forward<Callback>(callback)(std::forward<Args>(args)...);.

Поэтому такая реализация process_and_call несовершенна. Как можно это исправить?

Использовать std::invoke. Это функция буквально создана, чтобы вызывать все, что только можно вызвать. Она конечно же написана на вариабельных шаблонах, чтобы вы могли передать туда все, что душе угодно:

template< class F, class... Args >  
std::invoke_result_t<F, Args...> invoke( F&& f, Args&&... args );


Давайте посмотрим на корректную реализацию process_and_call с использованием std::invoke:
template <typename Callback, typename... Args>
void process_and_call(Callback&& callback, Args&&... args) {
// some processing
std::invoke(std::forward<Callback>(callback), std::forward<Args>(args)...);
}


struct S {
void foo(int i) {}
};

process_and_call(&S::foo, S{}, 42);

Прекрасная функция, которая может сильно упростить работу с callback'ами.

Be universal. Stay cool.

#cppcore #template
  • ❤ 24
  • 👍 13
  • 🔥 9
  • 🤔 1
  • 🤯 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →