C++中在模板vector与Lambda中使用参数包问题
在Lambda中捕获可变模板参数并打印类型的解决方案
嘿,我懂你现在的困扰——照着Stroustrup《C++编程语言》里的建议尝试在Lambda中捕获可变模板参数,结果代码编译不过,就想实现个能打印可变参数类型的功能对吧?别慌,咱们来一步步把问题捋清楚,再给你可行的解决方案。
先说说你可能踩的坑
你大概率是尝试了直接在Lambda的捕获列表里写参数包展开,比如这样:
template<typename... Args> void print_types(Args&&... args) { // 这种写法会编译失败!Lambda捕获列表不支持直接展开参数包 auto lambda = [args...]() { (std::cout << typeid(Args).name() << " ", ...); }; lambda(); }
Stroustrup提到的“若需捕获可变模板参数,请使用...”,其实是指利用初始化捕获(C++14及以上支持)或者打包参数到tuple后再捕获,而不是直接在捕获列表里写args...。
可行的解决方案
方案1:C++14+兼容版(初始化捕获+类型标识)
这个方案不需要依赖C++20的新特性,用初始化捕获把类型信息打包,再通过折叠表达式展开打印:
#include <iostream> #include <typeinfo> // 自定义type_identity,兼容C++14/17(C++20可直接用std::type_identity) template<typename T> struct type_identity { using type = T; }; template<typename... Args> void print_types(Args&&... args) { // 用初始化捕获把每个参数的类型信息存起来 auto lambda = [types = type_identity<Args>()...]() { std::cout << "可变参数类型列表:"; // 折叠表达式展开每个类型并打印 ([&]() { std::cout << typeid(typename decltype(types)::type).name() << " "; }(), ...); std::cout << "\n"; }; lambda(); } int main() { print_types(1, "hello", 3.14f); return 0; }
方案2:C++20简洁版(模板Lambda)
如果你的环境支持C++20,模板Lambda会让代码更直观,直接在Lambda里接收类型参数包:
#include <iostream> #include <typeinfo> template<typename... Args> void print_types(Args&&...) { // C++20模板Lambda,直接处理类型参数包 auto lambda = []<typename... Ts>() { std::cout << "可变参数类型列表:"; (std::cout << typeid(Ts).name() << " ", ...); std::cout << "\n"; }; // 显式传入类型参数包调用Lambda lambda.template operator()<Args...>(); } int main() { print_types(1, "hello", 3.14f); return 0; }
结合Vector的扩展示例
如果要同时把参数存入Vector(比如用variant存储多类型),再打印类型,可以这样写:
#include <iostream> #include <vector> #include <variant> #include <typeinfo> template<typename T> struct type_identity { using type = T; }; template<typename... Args> void vector_and_print(Args&&... args) { // 用variant存储不同类型的元素到vector std::vector<std::variant<Args...>> vec; (vec.emplace_back(std::forward<Args>(args)), ...); // Lambda捕获类型信息并打印 auto lambda = [types = type_identity<Args>()...]() { std::cout << "Vector中元素的类型:"; ([&]() { std::cout << typeid(typename decltype(types)::type).name() << " "; }(), ...); std::cout << "\n"; }; lambda(); } int main() { vector_and_print(10, std::string("test"), 2.718); return 0; }
小提示
typeid(T).name()返回的是编译器“混淆”后的类型名,不同编译器(比如GCC、Clang、MSVC)输出可能不一样,要是需要更可读的类型名,可以用Boost.TypeIndex这类第三方库,调试场景下typeid足够用啦。- 折叠表达式是C++11引入的,用来展开参数包非常方便,一定要掌握这个语法哦~
内容的提问来源于stack exchange,提问作者nodeover
相关产品推荐
相关产品推荐

