本文记录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) { … }
使用举例:

  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]

    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 可以用于更多的编译期计算场景,甚至作为非类型模板参数。

    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 进行默认构造和赋值。

    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捕获列表中直接展开参数包。

	// 接收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
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐