std::invoke, std::invoke_r
Материал из cppreference.com
< cpp | utility | functional
Определено в заголовочном файле <functional> | ||
(1) | ||
template<class F, class... Args> std::invoke_result_t<F, Args...> | (начиная с C++17) (до C++20) | |
template<class F, class... Args> constexprstd::invoke_result_t<F, Args...> | (начиная с C++20) | |
template<class R, class F, class... Args> constexpr R invoke_r( F&& f, Args&&... args)noexcept(/* смотрите ниже */); | (2) | (начиная с C++23) |
1) Вызвать объект Callablef с параметрами args, как
INVOKE
(std::forward<F>(f), std::forward<Args>(args)...). Эта перегрузка участвует в разрешении перегрузки, только если std::is_invocable_v<F, Args...> равно true.2) Вызвать объект Callablef с параметрами 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>constexprbool is_reference_wrapper_v =false;template<class U>constexprbool 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){ifconstexpr(std::is_function_v<Pointed>){ifconstexpr(std::is_base_of_v<C, std::decay_t<T1>>)return(std::forward<T1>(t1).*f)(std::forward<Args>(args)...);elseifconstexpr(is_reference_wrapper_v<std::decay_t<T1>>)return(t1.get().*f)(std::forward<Args>(args)...);elsereturn((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);}else{ static_assert(std::is_object_v<Pointed>&& sizeof...(args)==0);ifconstexpr(std::is_base_of_v<C, std::decay_t<T1>>)returnstd::forward<T1>(t1).*f;elseifconstexpr(is_reference_wrapper_v<std::decay_t<T1>>)return t1.get().*f;elsereturn(*std::forward<T1>(t1)).*f;}}}// пространство имён detail template<class F, class... Args>constexprstd::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)noexcept(std::is_nothrow_invocable_v<F, Args...>){ifconstexpr(std::is_member_pointer_v<std::decay_t<F>>)return detail::invoke_memptr(f, std::forward<Args>(args)...);elsereturnstd::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...>){ifconstexpr(std::is_void_v<R>) std::invoke(std::forward<F>(f), std::forward<Args>(args)...);elsereturn 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) | вызывает функцию с кортежем аргументов (шаблон функции) |