当前位置: 首页 > news >正文

可变参数包 和 lambda表达式

在 C++ 中,参数包(Parameter Pack) 分为两种类型:


1. 类型参数包(Type Parameter Pack)

作用:表示一个类型的序列,用于模板编程中的类型推导和生成。
语法:在模板参数列表中使用 typename... 或 class...
典型用途:泛型编程、可变参数模板。

示例

cpp

template <typename... Args>  // Args 是类型参数包
class Tuple {// 可存储任意数量和类型的元素
};// 使用
Tuple<int, double, std::string> t;  // Args = {int, double, std::string}

2. 形参参数包(Function Parameter Pack)

作用:表示一个值的序列,用于函数参数列表。
语法:在函数参数列表中使用 Args... args(需依赖类型参数包)。
典型用途:可变参数函数。

示例

cpp

template <typename... Args>
void print(Args... args) {  // args 是形参参数包//
}// 使用
print(1, 3.14, "hello");  // args = {1, 3.14, "hello"}
关键操作
  • 递归处理:通过模板递归展开形参参数包(C++11/14)。

    cpp

    template <typename T>
    void print(T t) {std::cout << t << "\n";
    }template <typename T, typename... Args>
    void print(T t, Args... args) {std::cout << t << ", ";print(args...);  // 递归展开
    }

二者关系

  • 类型参数包typename... Args)定义了一组类型。

  • 形参参数包Args... args)是基于类型参数包生成的一组值。

  • 配合使用:形参参数包必须依赖类型参数包。

完整示例

cpp

template <typename... Types>                  // 类型参数包
void bar(Types... values) {                  // values 是形参参数包std::tuple<Types...> data(values...);    // 同时展开类型和值
}bar(42, "hello");  // Types = {int, const char*}, values = {42, "hello"}

应用场景

  1. 可变参数模板、可变参数函数

    • 如 std::tuplestd::variant 的底层实现。

  2. 完美转发

    cpp

    template <typename... Args>
    void wrapper(Args&&... args) {target(std::forward<Args>(args)...);  // 保持值类别
    }

Lambda 表达式的底层本质上是一个编译器生成的匿名仿函数类对象,下面详细解释它的工作原理和底层实现:


1. Lambda 表达式的基本结构

一个简单的 Lambda 表达式:

cpp

auto lambda = [](int x, int y) { return x + y; };

编译器会将其转换为类似以下的匿名仿函数类

编译器生成的等效代码

cpp

// 编译器生成的匿名仿函数类
class __AnonymousLambdaClass {
public:// 重载 operator(),自己不写返回类型底层就用auto推导auto operator()(int x, int y) const {return x + y;}
};// Lambda 实例化
__AnonymousLambdaClass lambda;  // 相当于 auto lambda = [](int x, int y) { ... };

2. Lambda 的底层实现细节

(1) Lambda 捕获列表 → 仿函数类的成员变量

如果 Lambda 捕获了外部变量,这些变量会成为该匿名类的成员变量

cpp

int a = 10, b = 20;
auto lambda = [a, &b](int x) { return a + x + b; };

编译器生成的类

cpp

class __AnonymousLambdaClass {
private:int a;   // 值捕获 → 拷贝存储int& b;  // 引用捕获 → 存储引用
public:// 构造函数初始化捕获的变量__AnonymousLambdaClass(int a_, int& b_) : a(a_), b(b_) {}auto operator()(int x) const {return a + x + b;}
};// 实例化 Lambda
__AnonymousLambdaClass lambda(a, b);
捕获方式的影响
捕获方式存储方式是否可修改外部变量
[x]值拷贝 (const)❌ 不能修改
[&x]引用 (int&)✅ 可以修改
[=]所有变量值拷贝❌ 不能修改
[&]所有变量引用✅ 可以修改
[this]捕获当前类 this可访问类成员

(2) mutable 关键字 → 移除 operator() 的 const

默认情况下,Lambda 的 operator() 是 const 的,即不能修改值捕获的变量。如果加上 mutable,则允许修改:

cpp

int x = 10;
auto lambda = [x]() mutable { x++; };

编译器生成的类

cpp

class __AnonymousLambdaClass {
private:int x;  // 值捕获,但允许修改
public:__AnonymousLambdaClass(int x_) : x(x_) {}// 注意:没有 const 修饰!auto operator()() {x++;  // 允许修改}
};

(3) 返回类型推断

如果 Lambda 的返回类型可以自动推导(如 return x + y;),编译器会自动推断。也可以手动指定:

cpp

auto lambda = [](int x, int y) -> int { return x + y; };

生成的 operator() 返回类型

cpp

auto operator()(int x, int y) const -> int {return x + y;
}

3. Lambda 的底层优化

(1) 无捕获的 Lambda → 可转换为函数指针

如果 Lambda 不捕获任何变量,lambda底层为函数:

cpp

auto lambda = [](int x) { return x * 2; };
int (*func_ptr)(int) = lambda;  

底层实现

cpp

// 编译器生成一个静态函数(实际名称可能不同)
static int __LambdaHelper_1234(int x) {return x * 2;
}// Lambda 对象的行为(实际是函数指针)
auto lambda = &__LambdaHelper_1234;// 因此可以赋值给函数指针
int (*func_ptr)(int) = lambda;

http://www.xdnf.cn/news/343639.html

相关文章:

  • 代码简洁之道
  • 公链钱包开发:技术逻辑与产品设计实践
  • 21、魔法传送阵——React 19 文件上传优化
  • 【Dv3Admin】Git 子模块在 Dv3admin 插件项目统一管理实践
  • SpringBoot的自动配置功能-笔记
  • 智能边缘计算系统:基于Python的创新应用
  • python3连接数据库工具类之Oracle
  • Day19 常见的特征筛选算法
  • 零拷贝的简单复习
  • Python变量作用域
  • C PRIMER PLUS——第6-2节:二维数组与多维数组
  • nginx 实现动静分离
  • 火影bug,未保证短时间数据一致性,拿这个例子讲一下Redis
  • Android Studio Gradle 中 只显示 Tasks 中没有 build 选项解决办法
  • 【Science Advances】北京邮电大学突破:基于MEMS-超表面的多阶涡旋光束高速切换技术
  • 缓冲区溢出分析
  • Java网络编程:深入剖析UDP数据报的奥秘与实践
  • WordPress插件depicter存在SQL注入漏洞(CVE-2025-2011)
  • Nginx 配置多个监听端口
  • 文件包含漏洞
  • 【JavaEE】TCP/IP协议(模型)
  • 使用ESPHome烧录固件到ESP32-C3并接入HomeAssistant
  • 森林生态学研究深度解析:R语言入门、生物多样性分析、机器学习建模与群落稳定性评估
  • WPF主窗体子窗体关联方法
  • WPF中解决数据绑定不匹配的问题
  • 中继器的作用
  • AI开发跃迁指南(第三章:第四维度2——weaviate cloud、weaviate docker安装配置及使用连接示例)
  • 【计算机网络】用户从输入网址到网页显示,期间发生了什么?
  • Nginx1.26.2安装包编译安装并配置stream模块
  • V型球阀材质性能深度解析:专攻颗粒、料浆与高腐蚀介质的工业利器-耀圣