std::invoke, std::invoke_r
Материал из cppreference.com
<tbody>
</tbody>
<tbody class="t-dcl-rev t-dcl-rev-num ">
</tbody><tbody>
</tbody>
| Определено в заголовочном файле <functional>
|
||
| (1) | ||
template< class F, class... Args > std::invoke_result_t<F, Args...> invoke( F&& f, Args&&... args ) noexcept(/* смотрите ниже */); |
(начиная с C++17) (до C++20) |
|
template< class F, class... Args > constexpr std::invoke_result_t<F, Args...> invoke( F&& f, Args&&... args ) noexcept(/* смотрите ниже */); |
(начиная с C++20) | |
template< class R, class F, class... Args > constexpr R invoke_r( F&& f, Args&&... args ) noexcept(/* смотрите ниже */); |
(2) | (начиная с C++23) |
1) Вызвать объект Callable
f с параметрами args, как INVOKE(std::forward<F>(f), std::forward<Args>(args)...). Эта перегрузка участвует в разрешении перегрузки, только если std::is_invocable_v<F, Args...> равно true.2) Вызвать объект Callable
f с параметрами args, как INVOKE<R>(std::forward<F>(f), std::forward<Args>(args)...). Эта перегрузка участвует в разрешении перегрузки, только если std::is_invocable_r_v<R, F, Args...> равно true.Параметры
| f | — | Callable объект для вызова |
| args | — | аргументы для передачи f
|
Возвращаемое значение
1) Значение, возвращаемое
f.2) Значение, возвращаемое
f, неявно преобразуется в R, если R не равно void. Иначе ничего.Исключения
1)
спецификация noexcept:
noexcept(std::is_nothrow_invocable_v<F, Args...>)2)
спецификация noexcept:
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)Возможная реализация
| invoke |
|---|
namespace detail
{
template<class>
constexpr bool is_reference_wrapper_v = false;
template<class U>
constexpr bool is_reference_wrapper_v<std::reference_wrapper<U>> = true;
template<class C, class Pointed, class T1, class... Args>
constexpr decltype(auto) invoke_memptr(Pointed C::* f, T1&& t1, Args&&... args)
{
if constexpr (std::is_function_v<Pointed>)
{
if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
return (t1.get().*f)(std::forward<Args>(args)...);
else
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
}
else
{
static_assert(std::is_object_v<Pointed> && sizeof...(args) == 0);
if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
return std::forward<T1>(t1).*f;
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
return t1.get().*f;
else
return (*std::forward<T1>(t1)).*f;
}
}
} // пространство имён detail
template<class F, class... Args>
constexpr std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
noexcept(std::is_nothrow_invocable_v<F, Args...>)
{
if constexpr (std::is_member_pointer_v<std::decay_t<F>>)
return detail::invoke_memptr(f, std::forward<Args>(args)...);
else
return std::forward<F>(f)(std::forward<Args>(args)...);
}
|
| invoke_r |
template<class R, class F, class... Args>
requires std::is_invocable_r_v<R, F, Args...>
constexpr R invoke_r(F&& f, Args&&... args)
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)
{
if constexpr (std::is_void_v<R>)
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
else
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
|
Примечание
| Макрос тест функциональности | Значение | Стандарт | Комментарий |
|---|---|---|---|
__cpp_lib_invoke |
201411L |
(C++17) | std::invoke
|
__cpp_lib_invoke_r |
202106L |
(C++23) | std::invoke_r
|
Пример
Запустить этот код
#include <functional>
#include <iostream>
#include <type_traits>
struct Foo
{
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum
{
void operator()(int i) const
{
std::cout << i << '\n';
}
};
int main()
{
// вызвать свободную функцию
std::invoke(print_num, -9);
// вызвать лямбду
std::invoke([]() { print_num(42); });
// вызвать функцию-элемент
const Foo foo(314159);
std::invoke(&Foo::print_add, foo, 1);
// вызвать (получить доступ к) элемент данных
std::cout << "num_: " << std::invoke(&Foo::num_, foo) << '\n';
// вызвать функциональный объект
std::invoke(PrintNum(), 18);
# if defined(__cpp_lib_invoke_r)
auto add = [](int x, int y) { return x + y; };
auto ret = std::invoke_r<float>(add, 11, 22);
static_assert(std::is_same<decltype(ret), float>());
std::cout << ret << '\n';
std::invoke_r<void>(print_num, 44);
# endif
}
Возможный вывод:
-9
42
314160
num_: 314159
18
33
44
Смотрите также
(C++11) |
создаёт объект функцию из указателя на элемент (шаблон функции) |
(C++11)(удалено в C++20)(C++17) |
выводит тип результата вызова вызываемого объекта с набором аргументов (шаблон класса) |
| проверяет, может ли тип быть вызван (как если бы std::invoke) с заданными типами аргументов (шаблон класса) | |
(C++17) |
вызывает функцию с кортежем аргументов (шаблон функции) |