std::invoke用于统一调用各类可调用对象,包括普通函数、成员函数指针、成员变量指针、函数对象、lambda及std::function;它不进行类型擦除,仅安全转发参数,且不改变生命周期语义。

std::invoke 用来调用什么?
std::invoke 的核心作用是统一调用各种可调用对象:普通函数、成员函数指针、成员变量指针、函数对象(含 lambda)、std::function,甚至带捕获的 lambda(只要能传入参数)。它不负责类型擦除或存储,只做“一次安全转发”。
你不需要它来调用普通函数或 lambda —— 直接 () 就行;但当你写泛型代码(比如实现自己的 std::apply 或回调调度器),且输入可能是任意可调用类型时,std::invoke 就成了必要工具。
调用成员函数指针必须传对象实例
这是最常出错的地方:传 std::invoke 成员函数指针时,第一个实参必须是对象(或其引用/指针),不能漏掉。编译器不会帮你补 this。
- ✅ 正确:
std::invoke(&MyClass::foo, obj, 123) - ✅ 也正确(用指针):
std::invoke(&MyClass::foo, &obj, 123) - ❌ 错误:
std::invoke(&MyClass::foo, 123)—— 缺少对象,编译失败
注意:如果 &MyClass::foo 是 const 成员函数,obj 也得是 const 引用或 const 对象,否则类型不匹配。
立即学习“C++免费学习笔记(深入)”;
调用成员变量指针返回的是值,不是引用
用 std::invoke 调用成员变量指针(如 &MyClass::data)时,它返回的是该成员的副本(按值返回),不是引用 —— 即使原成员是引用类型,std::invoke 也不自动转为引用。
- 假设
struct S { int& x; };,std::invoke(&S::x, s)返回int(而非int&) - 想获取引用?直接用点号或箭头:
s.x或s->x更清晰、更高效 -
std::invoke在这种场景下没优势,纯属语法冗余
lambda 和 std::function 都能直接 invoke,但注意捕获上下文
带捕获的 lambda 可以被 std::invoke 调用,但它不延长捕获变量的生命周期 —— 这和直接调用一样,属于常见误解点。
auto make_cb = []() {
int local = 42;
return [=]() { return local; }; // 捕获 copy
};
auto cb = make_cb();
std::invoke(cb); // ✅ 安全,local 已拷贝进 lambda
但如果是 [&] 捕获局部变量,再在作用域外 std::invoke,就和直接调用一样会 UB:
{
int x = 100;
auto bad = [&]() { return x; };
// x 离开作用域后,bad 已悬空
std::invoke(bad); // ❌ 未定义行为
}
也就是说:std::invoke 不改变可调用对象本身的生命周期语义,它只是多一层转发。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/126945.html