std::invoke, std::invoke_r
来自cppreference.com
| 在标头 <functional> 定义
|
||
| (1) | (C++17 起) (C++20 起为 constexpr) |
|
| (2) | (C++23 起) | |
1) 以参数
args 调用可调用 (Callable) 对象 f,效果如同 INVOKE(std::forward<F>(f), std::forward<Args>(args)...)。此重载只有在 std::is_invocable_v<F, Args...> 是 true 时才会参与重载决议。2) 以参数
args 调用可调用 (Callable) 对象 f,效果如同 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)
R 是 void 时不返回,否则返回隐式转换到 R 的 f 的返回值。异常
1)
noexcept 说明:
noexcept(std::is_nothrow_invocable_v<F, Args...>)2)
noexcept 说明:
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)可能的实现
| invoke (1) |
|---|
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 T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template<class C, class Pointed, class Object, class... Args>
constexpr decltype(auto) invoke_memptr(Pointed C::* member, Object&& object,
Args&&... args)
{
using object_t = remove_cvref_t<Object>;
constexpr bool is_member_function = std::is_function_v<Pointed>;
constexpr bool is_wrapped = is_reference_wrapper_v<object_t>;
constexpr bool is_derived_object = std::is_same_v<C, object_t>
|| std::is_base_of_v<C, object_t>;
if constexpr (is_member_function)
{
if constexpr (is_derived_object)
return (std::forward<Object>(object) .* member)
(std::forward<Args>(args)...);
else if constexpr (is_wrapped)
return (object.get() .* member)(std::forward<Args>(args)...);
else
return ((*std::forward<Object>(object)) .* member)
(std::forward<Args>(args)...);
}
else
{
static_assert(std::is_object_v<Pointed> && sizeof...(args) == 0);
if constexpr (is_derived_object)
return std::forward<Object>(object) .* member;
else if constexpr (is_wrapped)
return object.get() .* member;
else
return (*std::forward<Object>(object)) .* member;
}
}
} // namespace 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<detail::remove_cvref_t<F>>)
return detail::invoke_memptr(f, std::forward<Args>(args)...);
else
return std::forward<F>(f)(std::forward<Args>(args)...);
}
|
| invoke_r (2) |
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, (1)
|
__cpp_lib_invoke_r |
202106L |
(C++23) | std::invoke_r, (2)
|
示例
运行此代码
#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::cout << "调用自由函数: ";
std::invoke(print_num, -9);
std::cout << "调用 lambda: ";
std::invoke([](){ print_num(42); });
std::cout << "调用成员函数: ";
const Foo foo(314159);
std::invoke(&Foo::print_add, foo, 1);
std::cout << "调用(访问)数据成员 num_: "
<< std::invoke(&Foo::num_, foo) << '\n';
std::cout << "调用函数对象: ";
std::invoke(PrintNum(), 18);
#if defined(__cpp_lib_invoke_r)
auto add = [](int x, int y){ return x + y; };
std::cout << "调用 lambda 并转换结果为 float: ";
auto ret = std::invoke_r<float>(add, 11, 22);
static_assert(std::is_same<decltype(ret), float>());
std::cout << std::fixed << ret << "\n调用 print_num: ";
std::invoke_r<void>(print_num, 44);
#endif
}
可能的输出:
调用自由函数: -9
调用 lambda: 42
调用成员函数: 314160
调用(访问)数据成员 num_: 314159
调用函数对象: 18
调用 lambda 并转换结果为 float: 33.000000
调用 print_num: 44
参阅
(C++11) |
从成员指针创建出函数对象 (函数模板) |
(C++11)(C++20 移除)(C++17) |
推导以一组实参调用一个可调用对象的结果类型 (类模板) |
| 检查类型能否以给定的实参类型调用(如同以 std::invoke) (类模板) | |
(C++17) |
以一个实参的元组来调用函数 (函数模板) |