CppGuide社区 CppGuide社区
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
🔥C++面试
  • 第1章 C++ 惯用法与Modern C++篇
  • 第2章 C++开发工具与调试进阶
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 网络通信协议设计
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 服务其他模块设计
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 🔥C++游戏编程入门(零基础学C++)
  • 🔥使用C++17从零开发一个调试器 (opens new window)
  • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南统 (opens new window)
  • 🔥使用C++从零写一个C语言编译器 (opens new window)
  • 🔥从零用C语言写一个Redis
  • leveldb源码分析
  • libevent源码分析
  • Memcached源码分析
  • TeamTalk源码分析
  • 优质源码分享 (opens new window)
  • 🔥远程控制软件gh0st源码分析
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go系统接口编程
  • 高效Go并发编程
  • Go性能调优
  • Go项目架构设计
  • 🔥使用Go从零开发一个数据库
  • 🔥使用Go从零开发一个编译器 (opens new window)
  • 🔥使用Go从零开发一个解释器 (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
🔥C++面试
  • 第1章 C++ 惯用法与Modern C++篇
  • 第2章 C++开发工具与调试进阶
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 网络通信协议设计
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 服务其他模块设计
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 🔥C++游戏编程入门(零基础学C++)
  • 🔥使用C++17从零开发一个调试器 (opens new window)
  • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南统 (opens new window)
  • 🔥使用C++从零写一个C语言编译器 (opens new window)
  • 🔥从零用C语言写一个Redis
  • leveldb源码分析
  • libevent源码分析
  • Memcached源码分析
  • TeamTalk源码分析
  • 优质源码分享 (opens new window)
  • 🔥远程控制软件gh0st源码分析
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go系统接口编程
  • 高效Go并发编程
  • Go性能调优
  • Go项目架构设计
  • 🔥使用Go从零开发一个数据库
  • 🔥使用Go从零开发一个编译器 (opens new window)
  • 🔥使用Go从零开发一个解释器 (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
  • C++语言面试问题集锦 目录与说明
  • 第一章 auto与类型推导
  • 第二章 关键字static及其不同用法
  • 第三章 多态、继承和虚函数
  • 第四章 Lambda函数
    • 问题30:什么是立即调用的Lambda函数?
    • 问题31:Lambda表达式有哪些可用的捕获方式?
  • 第五章 C++中如何使用 const 限定符
  • 第六章 Modern C++的一些最佳实践
  • 第七章 智能指针
  • 第八章 引用、万能引用等
  • 第九章 C++20相关问题
  • 第十章 特殊函数及数量规则
  • 第十一章 C++面向对象设计
  • 第十二章 程序质量
  • 第十三章 标准模板库
  • 第十四章 杂项
  • cppinterviewmostaskedquestions
zhangxf
2025-03-27
目录

第四章 Lambda函数

# 第四章 Lambda函数

接下来的两个问题将围绕Lambda函数展开,这是C++11中最重要的特性之一。回答这些问题的前提是你了解Lambda函数是什么。

# 问题30:什么是立即调用的Lambda函数?

可以说,它们是被立即调用的Lambda函数。好吧,但“立即”是什么意思呢? 这意味着Lambda函数甚至不会被变量存储和引用,而是在创建它的地方,马上就调用它。 下面这个不是立即调用的Lambda函数:

auto  l = [](){return  42;}; 
int  fortyTwo = l(); 
1
2

在上述例子中,你可以复用这个Lambda函数,可以传递它,根据需要随时调用它。 另一方面,在下面这个例子中,你立即调用了Lambda函数,这意味着你不会存储Lambda函数本身。根据定义,立即调用的Lambda函数(IILFs)不能被存储。如果它们被存储了,就不是立即调用的。

auto  fortyTwo = [](){return  42;}(); 
1

为什么这个概念很强大且值得一提呢? 它有助于对变量进行复杂的初始化。这很重要,因为帮助C++编译器的一个好方法是将所有不应该改变的变量声明为const。 在大多数情况下,这很简单,你只需在类型旁边加上const,并当场初始化变量。但你可能会遇到手中有不同可能值的情况。 让我们从一个简单的例子开始。

// Bad  Idea
std::string someValue; 
if  (caseA) {
    return  std::string{"Value A"};
} else  {
    return  std::string{"Value B"};
}
1
2
3
4
5
6
7

这样不好,因为这样的话someValue不是const类型的。我们能把它变成const类型吗?当然可以。我们可以使用三元运算符。

const  std::string someValue = caseA ? std::string{"Value A"} : std::string{"Value B"};
1

非常简单。 但是如果有3种或更多不同的可能性呢?你有不同的选择,其中之一就是立即调用的Lambda函数。

const  std::string someValue = [caseA, caseB] () {
    if  (caseA) {
        return  std::string{"Value A"};
    } else  if  (caseB) {
        return  std::string{"Value B"};
    } else  {
        return  std::string{"Value C"};
    }
}();
1
2
3
4
5
6
7
8
9

通过这种方式,你可以对const变量进行复杂的初始化,而且你不必为初始化逻辑寻找合适的位置或命名。 在性能方面,我们获得了使用const变量的所有性能优势,与三元运算符或辅助函数相比,没有任何性能损失。你可以在这里找到更多关于性能分析的详细信息⁶⁵ 。

# 问题31:Lambda表达式有哪些可用的捕获方式?

首先,一个Lambda表达式看起来是这样的:

capture -> returnType
1

捕获列表(capture)是一个由零个或多个捕获项组成的逗号分隔列表,可选择以捕获默认值开头。捕获列表定义了在Lambda函数体内可以访问的外部变量。 仅有的捕获默认值有:

  • &(隐式地通过引用捕获使用的自动变量)和
  • =(隐式地通过拷贝捕获使用的自动变量)。 如果存在任何一个捕获默认值,当前对象(*this)可以被隐式捕获。如果是隐式捕获,它总是通过引用捕获,即使捕获默认值是=。不过从C++20开始,使用捕获默认值=隐式捕获*this已被弃用。 以下是可用的捕获类型:
  • 按值捕获(自C++11起)
int  num;
auto  l = [num](){}
1
2
  • 作为包扩展的按值捕获(自C++11起)
template  <typename  Args>
void  f(Args... args) {
    auto  l = [args...] {
        return  g(args...);
    };
    l();
}
1
2
3
4
5
6
7
  • 按引用捕获(自C++11起)
int  num=42;
auto  l = [&num](){};
1
2
  • 作为包扩展的按引用捕获(自C++11起)
template  <typename  Args>
void  f(Args... args) {
    auto  l = [&args...] { return  g(args...);};
    l();
}
1
2
3
4
5
  • 对当前对象的按引用捕获(自C++11起)
auto  l = [this](){};
1
  • 带初始化器的按值捕获(自C++14起)
auto  l = [num=5](){};
1
  • 带初始化器的按引用捕获(自C++14起)
int  num=42;
auto  l = [&num2=num](){};
1
2
  • 对当前对象的按值捕获(自C++17起)
auto  l = [*this](){};
1
  • 带初始化器且作为包扩展的按值捕获(自C++20起)
template  <typename  Args>
auto  delay_invoke_foo(Args... args) {
    return   [...args=std::move(args)]() -> decltype(auto) {
        return  foo(args...);
    };
}
1
2
3
4
5
6
  • 带初始化器且作为包扩展的按引用捕获(自C++20起)
template  <typename  Args>
auto  delay_invoke_foo(Args... args) {
    return   [&...args=std::move(args)]() -> decltype(auto) {
        return  foo(args...);
    };
}
1
2
3
4
5
6
上次更新: 2025/03/27, 20:29:48
第三章 多态、继承和虚函数
第五章 C++中如何使用 const 限定符

← 第三章 多态、继承和虚函数 第五章 C++中如何使用 const 限定符→

最近更新
01
第一章 auto与类型推导
03-27
02
第二章 关键字static及其不同用法
03-27
03
C++语言面试问题集锦 目录与说明
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式