You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:27:40