掌握现代 C++:Lambda 在 C++14、C++17 和 C++20 中的演变

深入研究Lambda 在 C++14、C++17 和 C++20 中的演变

  • 一、背景
  • 二、C++14 中的 Lambda
    • 2.1、默认参数
    • 2.2、模板参数
    • 2.3、广义捕获
    • 2.4、从函数返回 lambda
  • 三、C++17 中的 Lambda
  • 四、C++20 中的 Lambda
  • 总结

一、背景

Lambda 是现代 C++ 最受欢迎的功能之一。自从在 C++ 11 中引入以来,它们在 C++ 代码中无处不在。而且,自从它们在 C++11 中出现以来,它们已经发展并获得了重要的功能。其中一些功能有助于编写更具表现力的代码,并且由于现在使用 lambda 非常普遍,因此花时间学习可以用它们做什么是非常值得的。

本文目标是剖析 lambda 的主要演变过程,但不是所有的小细节。对 lambda 的基础知识不了解可以阅读博主的另一篇文章,有详细介绍。

lambda 的一般演变是赋予它们手动定义的函数对象的功能。
在这里插入图片描述

二、C++14 中的 Lambda

在 C++14 中,lambda 获得了 4 项主要增强功能:

  • 默认参数
  • 模板参数
  • 广义捕获
  • 从函数返回 lambda

2.1、默认参数

在 C++14 中,lambda 可以采用默认参数,就像任何函数一样:

auto myLambda = [](int x, int y = 0) { 
    std::cout << x << '-' << y << '\n'; 
};

std::cout << myLambda(1, 2) << '\n';
std::cout << myLambda(1) << '\n';

输出:

1-2
1-0

2.2、模板参数

在 C++11 中必须定义 lambda 参数的类型:

auto myLambda = [](int x){ 
    std::cout << x << '\n'; 
};

在 C++14 中,可以让它们接受任何类型:

auto myLambda = [](auto&& x){ 
    std::cout << x << '\n'; 
};

即使不需要处理多种类型,这对于避免重复并使代码更紧凑和可读也很有用。例如,这种 lambda:

auto myLambda = [](namespace1::namespace2::namespace3::ACertainTypeOfWidget const& widget) { 
    std::cout << widget.value() << '\n'; 
};

变成:

auto myLambda = [](auto&& widget) { 
    std::cout << widget.value() << '\n'; 
};

2.3、广义捕获

在 C++11 中,lambda 只能捕获其作用域中的现有对象:

int z = 42;
auto myLambda = [z](int x){ 
    std::cout << x << '-' << z + 2 << '\n'; 
};

C++14 借助强大的lambda广义捕获,可以用几乎任何东西初始化捕获的值。示例:

int z = 42;
auto myLambda = [y = z + 2](int x) { 
    std::cout << x << '-' << y << '\n'; 
};

myLambda(1);

此代码输出以下内容:

1-44

2.4、从函数返回 lambda

Lambda 受益于 C++14 的语言功能:从函数返回,而无需指定返回类型。由于 lambda 的类型是由编译器生成的,因此在 C++11 中无法从函数返回 lambda。

/* what type should we write here ?? */ 
f()
{
    return [](int x){ return x * 2; };
}

在 C++14 中可以通过用作返回类型来返回 lambda。这在一段代码中间有一个大的 lambda 的情况下很有用。

void f()
{
    // ...
    int z = 42;
    auto myLambda = [z](int x) {
        // ...
        // ...
        // ...
    };
    // ...
}

可以将 lambda 打包到另一个函数中,从而引入另一个抽象级别:

auto getMyLambda(int z)
{
    return [z](int x) {
        // ...
        // ...
        // ...
    };
}

void f()
{
    // ...
    int z = 42;
    auto myLambda = getMyLambda(z);
    // ...
}

三、C++17 中的 Lambda

C++17 为 lambda 带来了一个重大增强:它们可以声明constexpr

constexpr auto times2 = [] (int n) { 
    return n * 2; 
};

然后,可以在编译时评估的上下文中使用此类 lambda:

static_assert(times2(3) == 6);

这在模板编程中特别有用。

注意:lambda 在 C++20 中变得更加有用。事实上,只有在 C++20 中,大多数 STL 算法才变得如此,并且它们可以与 lambda 一起使用,以创建在编译时评估的集合的复杂操作。
不过,有一个例外:std::array非变异访问操作在 C++ 14 中立即变为std::array constexpr,而在 C++17 中变为非变异访问操作constexpr

捕获 *this 的副本:lambda 在 C++17 中获得的另一个特性是捕获*this的副本的简单语法。
示例:

struct MyType{
    int m_value;
    auto getLambda()  {
        return [this](){ return m_value; };
    }
};

此 lambda 捕获this指针的副本。如果 lambda 的生存期超过对象的生存期,则可能会导致内存错误,例如:

auto lambda = MyType{42}.getLambda();
lambda();

由于MyType在第一个语句的末尾被销毁,因此第二个语句调用的lambda取消了this引用访问其m_value ,但this指向一个被销毁的对象。这会导致未定义的行为,通常是应用程序崩溃。

解决此问题是在 lambda 中捕获整个*this对象的副本。C++17 提供了语法来实现这一点。

struct MyType
{
    int m_value;
    auto getLambda() {
        return [*this](){ return m_value; };
    }
};

当然,在 C++ 14 中使用广义捕获已经可以实现相同的结果:

struct MyType
{
    int m_value;
    auto getLambda() {
        return [self = *this](){ return self.m_value; };
    }
};

只是C++17 使语法更好。

四、C++20 中的 Lambda

Lambda 在 C++ 20 中得到进一步发展,但其功能不如 C++ 或 C++ 17 那么基本。C++ 20 中 lambda 的一个增强功能是定义模板的经典语法,使它们更接近手动定义的函数对象:

auto myLambda = []<typename T>(T&& value){ std::cout << value << '\n'; };

这使得访问模板参数类型比使用 表达式(如auto&&)的 C++ lambda 模板更容易。

另一个改进是能够捕获可变参数包:

template<typename... Ts>
void f(Ts&&... args)
{
    auto myLambda = [...args = std::forward<Ts>(args)](){};
}

总结

本文讨论了lambda从C++14到C++20的主要改进。但也还有更多没有总结进来。这些主要功能伴随着许多小特性使 lambda 代码更易于编写。

深入研究 lambda 是更好地了解 C++ 语言的绝佳机会,这是一个值得投入的时间。

C++14
C++17
C++20
Auto return type deduction
Initializing captured variables
Generic Lambdas
Init-capture
Fold expressions
if constexpr in Lambdas
Capture initialization expression
= for capturing all variables
Consteval Lambdas

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/539697.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Day 23 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 总结篇

修剪二叉搜索树 给定一个二叉搜索树&#xff0c;同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[L, R]中 (R>L) 。你可能需要改变树的根节点&#xff0c;所以结果应当返回修剪好的二叉搜索树的新的根节点。 ​ 最直接的想法&#xff0…

【CSS】SVG图片属性及修改颜色

最近的开发中遇到了SVG不能修改颜色的问题&#xff0c;以前是直接用&#xff0c;没有研究过&#xff0c;现在搞个笔记记录下 SVG的属性&#xff1a; width:设置最终SVG图片的宽度height:设置最终SVG图片的高度viewbox&#xff1a;视区&#xff0c;在svg上截取一块&#xff0c…

【C++学习】C++智能指针:提高代码安全与性能的利器

文章标题 智能指针的提出智能指针概念及使用RAII 智能指针的原理C库多种智能指针详解版本一&#xff1a;std::auto_ptr&#xff08;C98&#xff09;1. std::auto_ptr 使用2. std::auto_ptr 原理3. std::auto_ptr 模拟实现 版本二&#xff1a;unique_ptr (C11)1. unique_ptr 的使…

Unity之PUN实现多人联机射击游戏的优化(Section 3)

目录 &#x1f4a3;一、准备工作 &#x1f4a3;二、生成弹头脚本的编写 &#x1f4a3;三、实现发射和伤害同步 手雷都加了在给狗剩加个火箭筒不过分吧。效果看GIF动图&#xff0c;分别是单机和联机的效果。 添加火箭筒依旧是在原有的基础上更改&#xff0c;我查看火箭筒模型…

基于STC12C5A60S2系列1T 8051单片机的LCD1602显示中文英文数字小数字库字符自定义字符的应用

基于STC12C5A60S2系列1T 8051单片机的LCD1602显示中文英文数字小数字库字符自定义字符的应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍LCD1602字符型液晶显示器介…

策略模式:灵活调整算法的设计精髓

在软件开发中&#xff0c;策略模式是一种行为型设计模式&#xff0c;它允许在运行时选择算法的行为。通过定义一系列算法&#xff0c;并将每个算法封装起来&#xff0c;策略模式使得算法可以互换使用&#xff0c;这使得算法可以独立于使用它们的客户。本文将详细介绍策略模式的…

算法——栈

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享关于栈相关的算法 如果有不足的或者错误的请您指出! 目录 1.删除字符中的所有相邻重复项1.1解析1.2题解 2.比较含退格的字符串2.1解析2.2题解 3.基本计算器II3.1解析3.2题解 4.…

清明美食制作|“心灵护航,增能培力”残疾人职业能力提升培养

为提高残疾人的动手能力&#xff0c;提升个人的自身素质和自主就业创业能力&#xff0c;弘扬中华民族传统文化&#xff0c;临近清明之际&#xff0c;淳安县从益舍社会工作服务中心于浪川乡展开了以“品尝春天味道 制作清明粿 清明美食制作”为主题的清明节活动。 【清明粿制作】…

【C语言__函数__复习篇1】

目录 前言&#xff1a; 一、C语言中函数的概念 二、库函数 2.1 库函数的概念 2.2 怎样自学库函数——以sqrt函数为例 三、自定义函数 3.1 自定义函数的概念 3.2 自定义函数的语法形式 3.3 函数的实参 3.4 函数的形参 3.5 实参与形参的关系 3.6 return语句 3.7 数组传参 …

O2OA开发平台如何查看数据表结构?

在访问后端api地址&#xff0c;页面最下方有列示平台的各个服务&#xff0c;点击进入可查看具体的表内容 后端api地址&#xff1a; http://{hostIP}/x_program_center/jest/list.html 其中&#xff1a;{hostIP}为中心服务器所在域名或者IP地址 如下图&#xff1a;

RA4000CE为汽车动力传动系统提供解决方案

目前汽车电气化的水平越来越高&#xff0c;其中比较显著的一个发展方向就是将发动机管理系统和自动变速器控制系统&#xff0c;集成为动力传动系统的综合控制(PCM)。作为汽车动力的核心部件&#xff0c;通过电子系统的运用&#xff0c;将外部多个传感器和执行环节的数据进行统一…

Go 自定义14位时间类型 yyyyMMddHHmmss

目录 功能 代码 功能 数据库或者接口时间类型&#xff0c;经常会使用14位的时间格式。每次都转换有点麻烦。可以自定义一个时间类型。 自定义类型需要实现json接口中的MarshalJSON与UnmarshalJSON两个函数&#xff0c;这样在做json编码解码时就会自动转为14位的时间格式了。…

基于flutter3.x+window_manager+getx桌面端仿macOS系统

flutter3_macui桌面端仿macOS系统实战项目完结啦&#xff01; 原创研发flutter3.19dart3.3window_managergetx等技术构建桌面版macOS系统。支持自定义毛玻璃虚化背景、Dock菜单多级嵌套自由拖拽排序、可拖拽弹窗等功能。 支持macOS和windows11两种风格。 使用技术 编辑器&…

【c++】优先级队列|反向迭代器(vector|list)

优先级队列的常用函数的使用 #include<iostream> #include<queue> using namespace std;int main() {priority_queue<int>st;st.push(1);st.push(7);st.push(5);st.push(2);st.push(3);st.push(9);while (!st.empty()){cout << st.top() << &qu…

【vue】watch 侦听器

watch&#xff1a;可监听值的变化&#xff0c;旧值和新值 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

openstack之neutron介绍

核心组件 neutron-server&#xff1a;提供API接口&#xff0c;把对应的api请求传给plugin进&#xff1b; neutron-plugin&#xff1a;管理逻辑网络状态&#xff0c;调用agent&#xff1b; neutron-agent&#xff1a;在provider network上创建网络对象&#xff1b; neutron-…

【Vue】实现仿微信输入@出现选择框

<div style"padding: 10px 10px" class"editor"><el-inputresizetype"textarea":rows"4"clearableplaceholder"请输入您的问题.."v-model"requestParams.prompt"input"handleInput"keydown.na…

C# WinForm —— 项目目录结构

1. WinForm 应用程序项目 Properties&#xff1a;属性文件夹存放了一个自动生成的类文件AssemblyInfo.cs&#xff0c;保存了一些应用程序集的一些信息引用存放了一些为应用程序提供所需的&#xff0c;某些功能的一些程序集&#xff08;dll文件&#xff09;等添加引用&#xff…

Html网页小游戏源代码

Html网页小游戏源代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Jello Jumping Game</title><meta name"viewport" content"widthdevice-width, initial-scale1"&…

【安全】挖矿木马自助清理手册

一、什么是挖矿木马 挖矿木马会占用CPU进行超频运算&#xff0c;从而占用主机大量的CPU资源&#xff0c;严重影响服务器上的其他应用的正常运行。黑客为了得到更多的算力资源&#xff0c;一般都会对全网进行无差别扫描&#xff0c;同时利用SSH爆破和漏洞利用等手段攻击主机。 …