如何不使用Lambda,用std::for_each和std::invoke调用容器内的std::function
问题:无需Lambda,单语句调用容器内的回调函数
我想完成一项练习:不使用Lambda表达式,仅通过一条语句调用容器中的所有回调函数。尝试用std::invoke实现,写了如下代码:
#include <algorithm> #include <functional> #include <iostream> int main() { std::function<void(void)> foo = []() { std::cout << "Foo !"; }; std::function<void(void)> bar = []() { std::cout << "Bar !"; }; const std::vector<std::function<void(void)>> callbacks = { foo, bar }; std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke); return 0; }
首次编译错误信息
main.cpp: In function ‘int main()’: main.cpp:12:22: error: no matching function for call to ‘for_each(std::vector >::const_iterator, std::vector >::const_iterator, )’ 12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke); | ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/11/algorithm:62, from main.cpp:1: /usr/include/c++/11/bits/stl_algo.h:3814:5: note: candidate: ‘template _Funct std::for_each(_IIter, _IIter, _Funct)’ 3814 | for_each(_InputIterator __first, _InputIterator __last, _Function __f) | ^~~~~~~~ /usr/include/c++/11/bits/stl_algo.h:3814:5: note: template argument deduction/substitution failed: main.cpp:12:22: note: couldn’t deduce template parameter ‘_Funct’ 12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke); | ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/11/algorithm:74, from main.cpp:1: /usr/include/c++/11/pstl/glue_algorithm_defs.h:42:1: note: candidate: ‘template __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> std::for_each(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Function)’ 42 | for_each(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Function __f); | ^~~~~~~~ /usr/include/c++/11/pstl/glue_algorithm_defs.h:42:1: note: template argument deduction/substitution failed: main.cpp:12:22: note: candidate expects 4 arguments, 3 provided 12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke); | ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Call Stack # Function File:Line Local Variables Variable Value Registers Register Value Display Expressions Expression Value Breakpoints and Watchpoints # Description
修改代码后的编译错误
尝试将代码修改为:
std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke<void(void)>);
仍编译失败,错误信息:
In file included from /usr/include/c++/11/algorithm:62, from main.cpp:1: /usr/include/c++/11/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<const std::function<void()>&*, std::vector<std::function<void()>> >; _Funct = void (*)(void (&)())]’: main.cpp:12:15: required from here /usr/include/c++/11/bits/stl_algo.h:3820:12: error: invalid initialization of reference of type ‘void (&)()’ from expression of type ‘const std::function’ 3820 | __f(*__first); | ~~~^~~~~~~~~~
解决方案
问题核心是std::invoke的使用方式不对:它是模板函数,直接传递给std::for_each时编译器无法正确推导参数,且它期望的原生函数引用类型和容器内的std::function不匹配。以下是几种无需Lambda的可行方案:
方案1:用std::mem_fn提取std::function的调用操作符
std::mem_fn可以直接提取std::function的operator(),生成能调用该操作的可调用对象:
std::for_each(callbacks.cbegin(), callbacks.cend(), std::mem_fn(&std::function<void()>::operator()));
方案2:用std::bind绑定std::invoke参数
通过std::bind明确将迭代器元素作为参数传递给std::invoke:
std::for_each(callbacks.cbegin(), callbacks.cend(), std::bind(std::invoke<void>, std::placeholders::_1));
方案3:C++20以上用std::bind_front简化绑定
如果编译器支持C++20,std::bind_front可以更简洁地完成绑定:
std::for_each(callbacks.cbegin(), callbacks.cend(), std::bind_front(std::invoke<void>));
原写法失败原因
- 直接传
std::invoke时,编译器无法推导_Funct模板参数,因为std::invoke本身是模板而非具体函数对象; - 指定
std::invoke<void(void)>后,它的签名要求接收原生函数引用,但容器内是const std::function<void()>,类型不匹配导致报错。
内容的提问来源于stack exchange,提问作者Oodini
相关产品推荐
相关产品推荐

