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