本文记录C++17新特性之invoke和invoke_result_t.
文章目录
- [第2章 C++17标准库特性](#第2章 C++17标准库特性)
-
- [2.9 std::invoke](#2.9 std::invoke)
-
- [2.9.1 invoke作用](#2.9.1 invoke作用)
- [2.9.2 使用举例](#2.9.2 使用举例)
- [2.9.3 invoke 和 function对比](#2.9.3 invoke 和 function对比)
- [2.10 std::invoke_result_t](#2.10 std::invoke_result_t)
第2章 C++17标准库特性
2.9 std::invoke
C++17之前,编写泛型代码处理回调时,调用不同的"可调用对象"(普通函数、函数指针、成员函数指针、以及仿函数(Functors)和 Lambda 表达式)时,需要不同的调用形式:
- 对于普通函数/Lambda/函数对象,直接调用f(args...)
- 对于成员函数指针,调用方式,(obj.*f)(args...) 或 (ptr->*f)(args...)
针对这种不一致的调用,在实现时,需要使用SFINAE模板元代码区别这些情况。
C++17 将这种复杂的逻辑标准化为 std::invoke,让普通开发者也能轻松编写通用的回调逻辑。
2.9.1 invoke作用
invoke包含在 中,核心作用:以统一的语法调用任何可调用对象。
2.9.2 使用举例
示例1:invoke调用不同的可调用对象。
cpp
// 1. 普通函数
void printNum(int i) {
std::cout << "Function: " << i << std::endl;
}
// 2. 仿函数 (Functor)
struct Printer {
void operator()(int i) const {
std::cout << "Functor: " << i << std::endl;
}
};
// 3. 类成员
struct Foo {
int value = 100;
void print(int i) {
std::cout << "Member Function: " << i + value << std::endl;
}
};
void test()
{
// 调用普通函数
std::invoke(printNum, 10);
// Function: 10
// 调用 Lambda
std::invoke([](int i) { std::cout << "Lambda: " << i << std::endl; }, 20);
// Lambda: 20
// 调用仿函数
Printer p;
std::invoke(p, 30);
// Functor: 30
// 调用成员函数 (注意:第一个参数必须是对象实例或指针)
Foo f;
std::invoke(&Foo::print, f, 40); // 传对象
std::invoke(&Foo::print, &f, 50); // 传指针
//Member Function : 140
// Member Function : 150
}
示例2:编写一个函数执行器,可执行任何函数。
cpp
// decltype(auto) 返回值
template<typename Callable,typename ...Args>
decltype(auto) logAndExecute(Callable&& func, Args &&...args)
{
// 使用invoke 统一调用
if constexpr (std::is_void_v< std::invoke_result_t<Callable, Args...> >)
{
std::invoke(std::forward<Callable>(func), std::forward<Args>(args)...);
cout << "函数返回void类型,无返回值可打印。" << endl;
}
else
{
decltype(auto) ret = std::invoke(std::forward<Callable>(func), std::forward<Args>(args)...);
return ret;
}
}
struct Worker
{
void dowork(int id)
{
std::cout << "Working on " << id << std::endl;
}
};
void test()
{
// 1 调用普通函数
auto result = logAndExecute([](int x, int y) {
return x + y;
}, 10, 20);
std::cout << "Result: " << result << std::endl;
// Result: 30
// 2 调用成员函数
Worker w;
logAndExecute(&Worker::dowork, &w, 42);
// Working on 42
}
2.9.3 invoke 和 function对比
std::function 是一个"容器":用于存储可调用对象,以便在未来某个时刻调用。它涉及类型擦除和运行时开销。
std::invoke 是一个"动作":用于立即执行可调用对象,统一调用语法。它通常用于泛型编程,零运行时开销。

2.10 std::invoke_result_t
见 模板与泛型编程笔记。
https://blog.csdn.net/weixin_43916755/article/details/155234300