如何编写可捕获所有局部变量并遍历打印的C++ Lambda函数
答案
你想要的「自动捕获当前作用域所有局部变量、新增变量无需修改lambda逻辑即可自动输出」的需求,纯标准C++无法直接实现,核心原因如下:
- C++没有提供任何编译期/运行时遍历当前作用域所有变量的语法或标准库接口,作用域内的变量列表仅在编译前端的语法分析阶段存在,不会生成可供代码访问的元数据。
- Lambda的默认值捕获
[=]的逻辑是仅捕获lambda体内显式用到的变量,你没有在lambda中写出名称的局部变量,哪怕定义了也不会被捕获到闭包中,完全无法访问。 - 即便你手动捕获了所有变量,C++也没有标准方式遍历lambda闭包的所有成员变量,需要依赖非标准编译器扩展,兼容性极差,不建议在生产环境使用。
可行替代方案
你可以把需要输出的局部变量统一打包到std::tuple中,通过编译期遍历tuple的方式实现需求,新增变量仅需在tuple中添加对应条目即可,符合你期望的「新增变量仅需少量修改」的要求,可运行代码如下:
#include <iostream> #include <string_view> #include <tuple> template <typename T> constexpr auto type_name() noexcept { std::string_view name, prefix, suffix; #ifdef __clang__ name = __PRETTY_FUNCTION__; prefix = "auto type_name() [T = "; suffix = "]"; #elif defined(__GNUC__) name = __PRETTY_FUNCTION__; prefix = "constexpr auto type_name() [with T = "; suffix = "]"; #elif defined(_MSC_VER) name = __FUNCSIG__; prefix = "auto __cdecl type_name<"; suffix = ">(void) noexcept"; #endif name.remove_prefix(prefix.size()); name.remove_suffix(suffix.size()); return name; } int main() { int var1 {1}, var2 {2}, var3{3}; float f1 {1.1f}, f2 {2.2f}; char letter {'a'}; // 所有需要输出的变量统一打包到tuple,新增变量仅需在此处添加 auto all_vars = std::make_tuple(var1, var2, var3, f1, f2, letter); auto myLambdaThatPrintsAll = [=] { std::apply([](auto&&... varIter) { // 折叠表达式遍历所有tuple元素 ((std::cout << "Type is: " << type_name<decltype(varIter)>() << "\n" << "Value is: " << varIter << "\n\n"), ...); }, all_vars); }; myLambdaThatPrintsAll(); return 0; }
上述代码运行输出和你期望的效果完全一致,新增变量时仅需在std::make_tuple的参数列表里添加对应变量即可,不需要修改lambda内部的遍历逻辑。
内容的提问来源于stack exchange,提问作者Matthew Pittenger
相关产品推荐
相关产品推荐

