文章目录
- [第一章 C++20核心语法特性](#第一章 C++20核心语法特性)
-
- [1.9 Lambda 改进](#1.9 Lambda 改进)
-
- [1.9.1. 模板Lambda使用](#1.9.1. 模板Lambda使用)
- [1.9.2 废弃[=]隐士捕获](#1.9.2 废弃[=]隐士捕获)
- [1.9.3 支持constexpr Lambda表达式](#1.9.3 支持constexpr Lambda表达式)
- [1.9.4 无状态 Lambda 的默认构造与赋值](#1.9.4 无状态 Lambda 的默认构造与赋值)
- [1.9.5 包展开](#1.9.5 包展开)
本文记录C++20新特性之Lambda 改进。
第一章 C++20核心语法特性
1.9 Lambda 改进
Lambda 表达式自 C++11 引入以来,已成为现代 C++ 编程不可或缺的一部分。C++20 对 Lambda 进行了多项重要的增强,使其在泛型编程、编译期计算以及捕获机制上变得更加强大和安全。
下面对Lambda的改进进行总结说明。
1.9.1. 模板Lambda使用
这是Lambda最明显的改进,直接在Lambda后边加了。
作用:允许我们访问类型名 T,或者对类型进行约束。
语法:[](T x) { ... }
使用举例:
cpp
void test()
{
// C++14 写法,使用auto,但很难获取vector 内部的类型T
auto old_lambda = [](auto vec)
{
using T = typename decltype(vec)::value_type;
T temp = vec[0];
std::cout << temp << std::endl;
};
vector<int> vec = { 1,2,3 };
old_lambda(vec);
// 1
// C++20 写法,使用模板参数
auto new_lambda = []<typename T>(const std::vector<T>& vec)
{
T temp = vec[0];
std::cout << temp << std::endl;
};
new_lambda(vec);
// 1
}
1.9.2 废弃[=]隐士捕获
在 C++20 之前,[=] 会隐式捕获 this 指针。如果你在一个对象的成员函数中创建了一个 Lambda 并异步执行,而该对象在 Lambda 执行前被销毁了,Lambda 内部访问成员变量时就会崩溃(因为 this 悬空了)。
在C++20中,[=] 不再 隐式捕获 this。如果需要捕获,必须显示写出, [=,this]
cpp
struct Worker
{
int value = 100;
void doWork() {
// C++17: [=] 默默捕获了 this,容易让人误以为是拷贝了 value
// C++20: 编译器会警告,建议显式写出 [=, this]
auto lambda = [=, this]() {
return value; // 访问 this->value
};
}
};
1.9.3 支持constexpr Lambda表达式
C++17 中 Lambda 可以在 constexpr 中使用,但限制较多。C++20 进一步放宽了限制,使得 Lambda 可以用于更多的编译期计算场景,甚至作为非类型模板参数。
cpp
void test()
{
// C++20: Lambda 可以直接在编译期求值
constexpr auto add = [](int a, int b) { return a + b; };
static_assert(add(10, 20) == 30); // 编译期断言通过
}
1.9.4 无状态 Lambda 的默认构造与赋值
在 C++20 之前,即使 Lambda 没有捕获任何变量(无状态),也不能被默认构造或赋值。这使得我们很难将 Lambda 类型用作 std::map 的 Key 或存储在某些容器中。
C++20 允许无状态 Lambda 进行默认构造和赋值。
cpp
int test()
{
auto greater = [](int a, int b)
{
return a > b;
};
// C++20 之前:编译错误,decltype(greater) 没有默认构造函数
// C++20:合法
std::map<int, int, decltype(greater)> myMap;
// 也可以直接赋值
decltype(greater) g2;
g2 = greater;
return 0;
}
1.9.5 包展开
在C++20中,可以在Lambda捕获列表中直接展开参数包。
cpp
// 接收0个或多个参数的包装函数
template<typename ... Args>
void wrapper(Args&& ... args)
{
// C++20: 直接转发参数包到 Lambda
auto lambda = [](auto&& ... innerArgs) {
// 使用 C++17 折叠表达式来处理参数包
std::cout << "Lambda received: ";
// 这个表达式会展开,依次打印所有参数,并用空格分隔
((std::cout << innerArgs << " "), ...);
std::cout << std::endl;
};
lambda(std::forward<Args>(args)...);
}
void test()
{
// 调用1:传入不同类型的字面量
wrapper(10, "hello", 3.14, 'A');
// Lambda received: 10 hello 3.14 A
// 调用2:传入变量
std::string my_str = "world";
int my_int = 42;
wrapper(my_str, my_int);
// Lambda received: world 42
}
}