TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #726 3.86K
Все вызываемые сущности в С++. Ч2
#опытным

Продолжаем перечислять все сущности, которые можно "вызывать" в С++.

И начинаем с продолжения перечисления всего, что относится к функторам:

👉🏿👉🏿 Лямбды

Там, где говорят про функторы, всегда водятся лямбды. Лямбды - это такие карманные функциональные объекты, которые определяются на ходу. У них также определен соответствующий оператор вызова operator(). Вот как может выглядеть код из предыдущего пункта с помощью лямбды:

int start = 5;
int step = 2;

auto gen = [current = start, step]() mutable {
return std::exchange(current, current + step);
};

std::vector<int> numbers(5);
std::generate(numbers.begin(), numbers.end(), gen);


Накидайте огней, если хотите узнать, как 3 строчки из лямбды в предыдущем посте превратились в одну с помощью std::exchange)

👉🏿👉🏿 Объект класса с определенным оператором приведения к указателю на функцию

Солидная часть подписчиков даже не слышала о такой сущности. Но работает это тривиально: при "вызове" такого объекта он кастится к указателю на функцию и уже с его помощью реально делается вызов:

class FunctionObjectCast {
public:
using fun_ptr = int ()(int);
// Оператор приведения к указателю на функцию
operator fun_ptr() {
return &staticMethod;
}

// Статический метод, который будет вызываться через указатель
static int staticMethod(int x) {
return x * 2;
}
};

FunctionObjectCast obj;
obj(42); // cast here


Но даже, если вы ни разу не слышали про функторы такого вида, то с высокой долей вероятности все равно неявно пользовались им. Это конечно же лямбды без захвата.

👉🏿👉🏿 Лямбды без захвата. Именно с помощью оператора приведения к указателю на функцию лямбды без захвата можно маскировать под указатели на функции. Это позволяет использовать их в качестве коллбэков к сишным функциям или колдовать такую магию.

std::vector<int> nums = {5, 3, 9, 1};
std::qsort(nums.data(), nums.size(), sizeof(int),
[](const void* a, const void* b) -> int {
return ((int)a - (int)b);});


std::qsort принимает последним параметром именно указатель на функцию, поэтому конкретно в этом кейсе и срабатывает приведение к этому указателю.

В случае привычного вызова самой лямбды используется operator().

👉🏿 Нестатический метод

struct Handler {
void foo(int a) {
std::cout << "Non-static method: " << a << std::endl;
}
};

Handler{}.foo(42);


👉🏿 Указатель на нестатический метод. Если вы хотите передать метод класса в качестве коллбэка, то вам необходимо это делать через указатель на метод. Метод класса - это такая же функция, только первым параметром она неявно принимает this. Если делать явный вызов метода через указатель на него, то эта неявная передача становится явной:

struct Handler {
void foo(int a) {
std::cout << "Non-static method: " << a << std::endl;
}
};

auto non_static_method_ptr = &Handler::foo;
std::invoke(non_static_method_ptr, Handler{}, 42);


Чтобы вызвать метод класса по его указателю через std::invoke нужно вторым параметром передать объект класса, на котором мы хотим вызвать метод. Далее идут аргументы в порядке, определенном в методе.

Замечу, что использования оператора взятия адреса(&) перед именем метода здесь обязательно. Имена нестатических методов не имеют желания неявно приводится к указателям, как имена функций. Вот так нельзя:
std::invoke(Handler::foo, Handler{}, 42);

Это синтаксис для использования статических методов и компилятор будет ругаться.

👉🏿 Указатель на поле класса. Недавно обсуждали, что с помощью std::invoke можно "вызывать" поля класса. Неочевидно, но бывает полезно.

struct Payment {
double amount;
std::string category;
}

Payment p{100500, "confetki"};
std::cout << std::invoke(&Payment:amount, p) << std::endl;
// OUTPUT:
// 100500


Фух. Вроде все. Пишите, если что забыл.

Have all the tools. Stay cool.

#cppcore
  • 🔥 40
  • 👍 10
  • ❤ 4
  • ❤‍🔥 2
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 →