lambda
第一题
1 | auto* p = +[] {return 6; }; |
这里的 + 是什么作用?
这是一个非捕获的 lambda,自然可以生成对应转换函数转换为函数指针,这里的一元 + 是为了辅助推导,是为了创造合适的语境。自然理解为使用转换函数返回函数指针,+ 指针,符合规范
这里 auto*
的 *
可以去掉
第二题
1 | int main() { |
提问,打印p是多少?return a是多少?
答案: 1 43
解释:
如果变量满足下列条件,那么 lambda 表达式在使用它前不需要先捕获:该变量是非局部变量,或具有静态或线程局部存储期(此时无法捕获该变量),或者该变量是以常量表达式初始化的引用。
这里的捕获是
[=]
,但是其实写不写都无所谓,反正这个作用域就一个静态局部变量 a,你也无法捕获到这个变量。那么按照空类,p的大小一般来说自然也就是1了。
第三题
1 | int main() { |
上面的代码会输出什么? 1
解释:
如果捕获符列表具有默认捕获符,且未显式(以 this 或 *this)捕获它的外围对象,或任何在 lambda 体内可 [ODR 使用]的自动变量,或对应变量拥有自动存储期的结构化绑定 (C++20 起),那么在以下情况下,它隐式捕获之:
lambda 体 ODR 使用了该实体
或者,该实体在取决于某个泛型 lambda 形参的 (C++17 前)表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的 this->)。就此目的而言,始终认为 typeid 的操作数被潜在求值。即使实体仅在舍弃语句中被指名,它也可能会被隐式捕获。 (C++17 起)
潜在求值
或者,该实体在取决于某个泛型 lambda 形参的 (C++17 前)表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的 this->)。就此目的而言,始终认为 typeid 的操作数被潜在求值。即使实体仅在舍弃语句中被指名,它也可能会被隐式捕获。 (C++17 起)
typeid
或者,该实体在取决于某个泛型 lambda 形参的 (C++17 前)表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的 this->)。就此目的而言,始终认为 typeid 的操作数被潜在求值。即使实体仅在舍弃语句中被指名,它也可能会被隐式捕获。 (C++17 起)
舍弃语句
或者,该实体在取决于某个泛型 lambda 形参的 (C++17 前)表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的 this->)。就此目的而言,始终认为 typeid 的操作数被潜在求值。即使实体仅在舍弃语句中被指名,它也可能会被隐式捕获。 (C++17 起)
第四题
1 | int main() { |
请问打印多少?1
解释:
如果变量满足下列条件,那么 lambda 表达式在读取它的值前不需要先捕获: 该变量具有 const 而非 volatile 的整型或枚举类型,并已经用常量表达式初始化,或者 该变量是 constexpr 的且没有 mutable 成员。(这是表示即使不使用=捕获在这里的语境下直接用也没问题)
N没有被ODR使用,没有被捕获
第五题
1 | int main() { |
请问打印多少?
msvc:4,gcc:1,clang:1
解释:
1.这属于编译器优化的行为,因为就算不带上 [=]
,也能正常访问
2.读取编译时常量的值也不是ODR使用。
第六题
1 | void f(int, const int(&)[2] = {}) {} // #1 |
这段代码的运行结果是什么?msvc 和 gcc12.1 都是 1 4 4 4
解释:
该实体在取决于某个泛型 lambda 形参的(C++17 前)表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的this->)。就此目的而言,始终认为typeid的操作数被潜在求值。即使实体仅在舍弃语句中被指名,它也可能会被隐式捕获。(C++17 起)
先复习一下第四题的解释,我这里的代码全部都是[=]捕获的,你就算全部去掉,他们运行的结果是四个1,这也没任何问题,也符合先前说的规则
再举一个简单的例子:
1 | void f(int){} |
gcc和msvc都打印4,这不是重点,当我们把(auto a)这个形参去除了,gcc就打印1。跳转
我们脑补一下,最初gcc认为N没有被ODR使用(其实我也是这么认为的),但是判断是否捕获还有另一个规则,也就是我们解释的第一点那个泛型lambda,所以捕获了, 打印4,如果去除(auto a)的话就是1了
第七题
1 | int main() { |
打印多少?true
解释:
lambda 表达式上的异常说明异常说明应用于函数调用运算符或运算符模板。
第八题
1 | //1. |
- 如果变量满足下列条件,那么 lambda 表达式在读取它的值前不需要先捕获:
该变量具有const
而非volatile
的整型或枚举类型,并已经用常量表达式初始化,或者
该变量是constexpr
的且没有mutable
成员。 - 同上
- 同上
- 同上
- 这里需要特别说明一下,是读取值不需要先捕获,不是和第二题那种情况一样,可以直接使用,要区分,如果你改成
[=]
的话也就合法了