TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #723 4.35K
Ответ

Мы прям недавно обсуждали, что std::invoke позволяет вызвать указатель на метод класса, это у вас не должно было вызвать вопросов. Самая загвоздка вот тут:

auto fieldPtr = &Data::field;
std::invoke(fieldPtr, Data{});


fieldPtr здесь - это указатель на нестатическое поле класса.

Скорее всего у вас возникли такие вопросы: "Что значит вызвать поле класса?! Это вообще легально?".

И ответ на этот вопрос довольно контринтуитивный. Да, std::invoke помогает единообразно вызвать все похожие на функции сущности. То есть запускать на выполнение код. Но поле класса - это вообще говоря не код, а участок памяти. А указатель на поле класса - это оффсет от начала объекта. На функции это вообще не похоже.

Тем не менее вызов поля класса с помощью std::invoke - легальная операция. И ее результат - значение этого поля.

Странно? Безусловно. Есть ли у этого применения? Конечно!

В C++20 алгоритмах библиотеки ranges есть специальный параметр проекции. Это вызываемая сущность, которая помогает преобразовывать элементы диапазона перед обработкой.

Допустим мы хотим найти в диапазоне объект с максимальным значением определенного поля. Как бы мы это делали без диапазонов:

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

std::vector<Payment>
payments = {{100.0, "food"}, {200.0, "transport"}, {150.0, "food"},
{300.0, "entertainment"}, {50.0, "transport"}, {250.0, "food"},
{120.0, "food"}};

auto max = *std::max_element(
transactions.begin(), transactions.end(),
[](const auto& item1, const auto& item2) { return item1.amount < item2.amount; });


Классика: определяем кастомный компаратор для сравнения элементов. Но заметьте сколько кода повторяется. Не легче ли просто один раз указать, что сравнивать надо по полю amount? И библиотека диапазонов позволяет нам это сделать!

auto max = *std::ranges::max_element(payments, {}, [](const auto& elem){return elem.amount;});


Последний параметр проекции позволяет нам сказать, как нужно преобразовывать элементы последовательности перед сравнениями.

Но это все еще не идеал. Лямбда здесь кажется оверкиллом. Вот здесь-то вызов поля класса и пригождается:

auto max = *std::ranges::max_element(payments, {}, &Payment::amount);


Вот и все. Просто и красиво.

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

Пользуйтесь диапазонами и проекторами. Это полезные штуки, которые ощутимо упрощают код.

Be laconic. Stay cool.

#cpp20 #STL
  • ❤‍🔥 29
  • 👍 15
  • ❤ 10
  • 🔥 7
  • 😱 4
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
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 →