std::invoke 是 c++17 引入的统一调用工具,支持函数指针、成员函数指针、Lambda、函数对象及 std::bind 表达式等所有可调用类型,简化泛型代码中不一致的调用语法。

std::invoke 是 C++17 引入的一个实用工具,用来**统一调用各种可调用对象**——不管它是函数指针、成员函数指针、lambda、函数对象,还是带绑定的 std::bind 表达式,只要它“能被调用”,std::invoke 就能以一致的方式执行它。
解决“调用方式不统一”的痛点
在 C++17 之前,调用不同类型的可调用对象写法差异很大:
- 普通函数或函数对象:直接
f(a, b) - 指向对象成员函数的指针:需要先有对象,再用
(obj.*mf)(a, b)或(ptr->*mf)(a, b) - 指向数据成员的指针:本质是“取值”,也要用
obj.*mp这类特殊语法
这种碎片化让泛型代码(比如实现自己的包装器、延迟调用、回调分发)变得冗长又易错。std::invoke 把这些细节收拢了,你只管传对象 + 参数,它自动判断怎么调。
基本用法:两个核心形式
std::invoke(f, args...) 接收一个可调用对象 f 和一串参数,返回调用结果。
立即学习“C++免费学习笔记(深入)”;
- 如果
f是普通函数/lambda/函数对象:std::invoke(f, x, y)等价于f(x, y) - 如果
f是指向成员函数的指针:std::invoke(&C::func, obj, x)等价于obj.func(x)(支持左值/右值/指针) - 如果
f是指向数据成员的指针:std::invoke(&C::value, obj)等价于obj.value
它还能自动处理 std::reference_wrapper、std::bind 结果等包装类型,真正“一层封装调到底”。
典型使用场景
它不是日常写业务逻辑时手动敲的工具,而是底层泛型设施的基石:
- 实现自己的包装器:比如写一个
delayed_call或try_invoke,内部统一用std::invoke执行,不用为每种可调用类型写分支 - std::Thread / std::async 的参数转发:它们内部就依赖
std::invoke来启动任意可调用体(这也是为什么你能直接传成员函数指针给std::thread) - any_invocable 或 callback 容器的执行逻辑:存储多种可调用对象后,靠
std::invoke统一触发
注意点:不是万能胶,但很务实
std::invoke 不做类型擦除,也不改变调用语义——它只是把已有语法糖成一个接口。它不会帮你转型、不会捕获异常、也不会自动移动参数(该转发的仍需 std::forward)。它的价值在于:让模板代码干净、安全、可读,避免手写 if constexpr 判断类型再选调用方式。
基本上就这些。