Daily bit(e) C++. std::invoke

Добавлено 30 сентября 2023 в 10:37

Daily bit(e) C++ #236, утилита из C++17, которая может вызывать любой вызываемый объект: std::invoke.

Daily bit(e) C++

std::invoke из C++17 – это утилита, которая может вызывать любой вызываемый объект с предоставленными аргументами. Обратите внимание, что сюда входят функции-члены и даже члены.

Если нам не нужны свойства стирания типа std::function или std::move_only_function, то более низкоуровневой альтернативой может стать std::invoke (с вызываемым объектом и аргументами, которые выводятся статически).

#include <functional>

// Вызов типовых вызываемых объектов
// (т.е. лямбды, функции...)
auto zero_arg = [](){ return 42; };
auto two_arg = [](int a, int b) { return a + b; };

int a = std::invoke(zero_arg);
// a == 42
int b = std::invoke(two_arg, 98, 2);
// b == 100


// Демонстрация вызова членов
struct X 
{
    int value;
    int get_value() { return value; }
    int add(int extra) { return value + extra; }
};

X x{42};

int c = std::invoke(&X::value, x);
// c == 42
int d = std::invoke(&X::get_value, x);
// d == 42
int e = std::invoke(&X::add, x, 42);
// e == 84


// Демонстрация использования std::invoke
// в качестве альтернативы для
// std::(move_only_)function.

#include <format>

int do_some_magic(int a, int b) { return a + b; }

// Кастомизация кода с std::(move_only_)function.
void operate(int a, int b, 
             std::move_only_function<void(std::string)> logger) 
{
    int c = do_some_magic(a,b);
    logger(std::format("Did some magic with {} and {},"
                       " the result was {}.", a, b, c));
}

// Статическая кастомизация кода с помощью вызываемого объекта.
void operate_static(int a, int b, auto&& logger) 
{
    int c = do_some_magic(a,b);
    std::invoke(std::forward<decltype(logger)>(logger), 
        std::format("Did some magic with {} and {},"
                    " the result was {}.", a, b, c));
}

#include <iostream>

auto logger1 = [](std::string line) { 
  std::cout << "Logger1: " << line << "\n"; 
};
auto logger2 = [](std::string line) {
  std::cout << "Logger2: " << line << "\n";
};

// Два разных вызываемых объекта, тип стерт:
operate(1,2,logger1);
operate(1,2,logger2);

// Два разных вызываемых объекта,
// две сгенерированные функции:
operate_static(1,2,logger1);
operate_static(1,2,logger2);

Открыть пример на Compiler Explorer.

Теги

C++ / CppDaily bit(e) C++STL / Standard Template Library / Стандартная библиотека шаблоновПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.