C++ Lambda表达式第一篇, 闭合(Closuretype)

C++ Lambda表达式第一篇, 闭合Closuretype

  • ClosureType::operator()(params)
    • auto 模板参数类型
    • 显式模板参数类型
    • 其他
  • ClosureType::operator ret(*)(params)()

lambda 表达式是唯一的未命名,非联合,非聚合类类型(称为闭包类型)的纯右值表达式,它在包含 lambda 的最小块作用域、类作用域或命名空间作用域中声明(出于 ADL 的目的)表达。

当且仅当 captures 为空时,闭包类型才是结构类型。

闭包类型具有以下成员,它们不能显式实例化、显式专门化或在友元声明中命名:

ClosureType::operator()(params)

ret operator()(params) { body }
template<template-params>
ret operator()(params) { body }

调用时,执行 lambda 表达式的主体。访问变量时,访问其捕获的副本(对于通过副本捕获的实体)或原始对象(对于通过引用捕获的实体)。

如果提供了operator()的参数列表,则为params,否则参数列表为空。

operator()的返回类型是trailing-type中指定的类型。

如果未提供 Trailing-type,则自动推导出operator() 的返回类型。

除非在 lambda 说明符中使用关键字 mutable,或者存在显式对象参数,否则 operator() 的 cv 限定符为 const,并且通过 copy 捕获的对象从内部不可修改这个运算符()。不允许显式 const 限定符。 operator() 从来都不是虚拟的,并且不能具有 volatile 限定符。

  • 如果operator() 满足constexpr 函数的要求,则它始终是constexpr。如果 lambda 说明符中使用了关键字 constexpr,那么,它也是 constexpr。
  • 如果 lambda 说明符中使用了关键字 consteval,则operator() 是立即函数。
  • 如果 lambda 说明符中使用了关键字 static,则operator() 是静态成员函数。
  • 如果 params 包含显式对象参数,则operator() 是显式对象成员函数。

auto 模板参数类型

对于 params 中类型指定为 auto 的每个参数,都会按照出现的顺序将发明的模板参数添加到 template-params 中。如果params对应的函数成员是函数参数包,则本发明的模板参数可以是参数包。

#include  <iostream>
#include  <iostream>
#include  <fstream>using namespace std;// generic lambda, operator() is a template with two parameters
auto glambda = [](auto a, auto&& b) { return a < b; };// generic lambda, operator() is a template with one parameter
auto vglambda = [](auto printer)
{return [=](auto&&... ts) // generic lambda, ts is a parameter pack{ printer(forward<decltype(ts)>(ts)...);// nullary lambda (takes no parameters):return [=] { printer(ts...); };};
};auto p = vglambda([](auto v1, auto v2, auto v3)
{cout << v1 << " " << v2 << " " << v3 << endl;
});int main() {	int   x = 100;bool b = glambda(3, (x / 10) - 3.14);cout << b << endl;b = glambda(3, (x / 20) - 3.14);cout << b << endl;auto q = p(1, 'a', 3.14); // outputs 1 a 3.14q();                      // outputs 1 a 3.14auto pp = vglambda(printf);pp("%s %d \n", "Sam", 45);
}

代码运行的屏幕输出

1
0
1 a 3.14
1 a 3.14
Sam 45

显式模板参数类型

如果 lambda 定义使用显式模板参数列表,则该模板参数列表将与 operator() 一起使用。对于 params 中类型指定为 auto 的每个参数,一个新的模板参数类型,将作为该模板参数列表的类型,直至到参数列表的末尾:

#include  <iostream>
#include  <iostream>
#include  <fstream>using namespace std;struct A
{A(int&& n) { cout << "rvalue overload, n=" << n << '\n'; }A(int& n)  { cout << "lvalue overload, n=" << n << '\n'; }
};class foo
{
public:template<class T1, class T2, class T3>foo(T1&& t1, T2&& t2, T3&& t3) :a1_{forward<T1>(t1)},a2_{forward<T2>(t2)},a3_{forward<T3>(t3)}{}private:A a1_, a2_, a3_;
};// generic lambda, operator() is a template with two parameters
auto glambda = []<class T>(T a, auto&& b) { return a < b; };// generic lambda, operator() is a template with one parameter pack
auto f1 = []<typename... Ts>(Ts&&... ts)
{return foo(forward<Ts>(ts)...);
};int main() {	int   x = 100;bool b = glambda(3, (x / 10) - 3.14);cout << b << endl;b = glambda(5.0, (x / 20) - 3.14);cout << b << endl;f1(1, 2, 4);
}
1
0
rvalue overload, n=1
rvalue overload, n=2
rvalue overload, n=4

其他

lambda 表达式上的异常规范exception适用于operator()。

为了名称查找、确定 this 指针的类型和值,以及访问非静态类成员,闭包类型的operator() 的主体可以认为是 lambda 表达式的一部分。

struct X
{int x, y;int operator()(int);void f(){// 下面的lambda表达式是成员函数 X::f[=]() -> int{return operator()(this->x + y); // X::operator()(this->x + (*this).y)// this has type X*};}
};

ClosureType::operator ret(*)(params)()

- 无捕获,非常规Lambda* using F = ret(*)(params);  operator F() const noexcept;* using F = ret(*)(params);* constexpr operator F() const noexcept;
- 无捕获,常规lambda* template<template-params>operator fptr_t<template-params>() const noexcept;* template<template-params>constexpr operator fptr_t<template-params>() const noexcept;

仅当 lambda 表达式的捕获列表为空时,才会定义此用户定义的转换函数。该函数是一个闭合对象的成员函数, 而且具有public, constexpr, 非虚、非显式 和 const noexcept特征。

如果函数调用运算符是立即函数,则此函数是立即函数。

通用的无捕获 lambda 具有一个用户定义的转换函数模板,它具有与 operator() 相同的新模板参数表。

#include  <iostream>using namespace std;void f1(int (*f)(int)) {int x = f(2);cout << "f=" << x << endl;
}void f2(char (*)(int)) {}
void h(int (*h)(int)) {  // #1int x = h(3);cout << "h=" << x << endl;
}void h(char (*)(int)) {} // #2auto glambda = [](auto a) { return a; };int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OKint main()
{f1(glambda); // OK
//	auto y = f2(glambda); // error: not convertibleh(glambda);  // OK: calls #1 since #2 is not convertibleauto x = glambda(1);cout << "x: " << x << endl;auto y = fpi(&x);cout << "y: " << y << endl;
}

转换函数的返回值是一个指向具有 C++ 语言链接的函数指针,调用该函数时,与在闭包类型的默认构造实例上调用闭包类型的函数调用运算符具有相同的效果。

转换函数(模板)返回的值是一个指向具有 C++ 语言链接的函数的指针,调用该函数时,具有与以下相同的效果:

对于非泛型 lambda,在闭包类型的默认构造实例上调用闭包类型的operator()。
对于泛型 lambda,在闭包类型的默认构造实例上调用泛型 lambda 相应的operator() 特化。
转换函数(模板)返回的值为

如果operator()是静态的,则为具有C++语言链接的指向该operator()的指针,
否则,指向具有 C++ 语言链接的函数的指针,在调用该函数时,具有与以下相同的效果:
对于非泛型 lambda,在闭包类型的默认构造实例上调用闭包类型的operator()。
对于泛型 lambda,在闭包类型的默认构造实例上调用泛型 lambda 相应的operator() 特化。

如果函数调用运算符为 constexpr,则此函数为 constexpr。

#include  <iostream>using namespace std;auto Fwd = [](int(*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };auto NC = [](auto a) { static int s; return a; };int main() {	static_assert(Fwd(C, 3) == 3);//	static_assert(Fwd(NC, 3) == 3); // error: no specialization can be constexpr because of static s
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【实习问题记录】Nodeclub本地部署

问题描述 在按照官方网站给出的教程一步一步操作以后发现出现以下报错&#xff1a; 问题分析 显示连接不上mongodb&#xff0c;分析报错可能是因为版本不匹配导致的&#xff0c;查看安装的mongodb版本发现是7.0.4&#xff0c;与目标版本不匹配&#xff0c;同时查看mongodb官…

我们所熟知的meme梗图也可以用AI生成了,老外都玩坏了。

meme梗图不知道大家看到过嘛&#xff1f;相信你们看见下面的图你就会大叫“卧槽”&#xff0c;原来是这种图&#xff0c;我以前经常狂刷不止&#xff0c;太有趣了。 其实meme是一个网络流行语&#xff0c;可译为模因。在大众非学术范围内也可翻译为我们所熟知的“梗”。其中“表…

SDK环境的安装(测试使用)

1、安装 将文件解压至目录,我的目录为:D:\Program Files\Android 解压后如下: 下载链接如下: sdk下载 提取码见文章最后: 2、配置环境 1、在环境变量中,选择系统变量,点击新建。 变量名:ANDROID_HOME 变量值:“你自己的android-sdk安装路径” (例如我的:D:\Pro…

CF1955C Inhabitant of the Deep Sea 题解

题目 模拟 首先想到模拟。 但是看到数据范围&#xff0c;模拟不了。 #include<bits/stdc.h> #include<cstring> #include<queue> #include<set> #include<stack> #include<vector> #include<map> #define int long long #define …

如何在 Linux 中高亮显示日志关键字

在 Linux 系统中&#xff0c;实时查看日志文件通常使用 tailf 命令&#xff0c;但 tailf 本身并不支持高亮显示关键字功能。通过结合 grep、sed 等工具&#xff0c;我们可以实现日志关键字高亮。本文将介绍几种高效的方法来实现这一目标。 方法一&#xff1a;使用 grep --color…

人机交互中有许多不满足紧致性条件的地方

紧致性条件通常用于描述拓扑空间的性质。一个拓扑空间被称为紧致的&#xff0c;如果它的任意开覆盖都有有限子覆盖。换句话说&#xff0c;对于任何开覆盖&#xff0c;都可以从中选取有限个开集&#xff0c;它们的并仍然覆盖整个空间。 满足紧致性条件的方法通常包括以下几种&am…

7月8日 四道经典单链表oj题

大家好呀&#xff0c;本博客目的在于记录暑假学习打卡&#xff0c;后续会整理成一个专栏&#xff0c;主要打算在暑假学习完数据结构&#xff0c;因此会发一些相关的数据结构实现的博客和一些刷的题&#xff0c;个人学习使用&#xff0c;也希望大家多多支持&#xff0c;有不足之…

CSS--表格自适应宽度并设置最小宽度

原文网址&#xff1a;CSS--表格自适应宽度并设置最小宽度_IT利刃出鞘的博客、-CSDN博客 简介 本文介绍怎样让HTML的表格自适应宽度。 Java技术星球&#xff1a;way2j.com 问题描述 默认样式下&#xff0c;表格会出现某一列很窄的情况&#xff1a; 代码&#xff1a; <h…

Redission 解锁异常:attempt to unlock lock, not locked by current thread by node id

标题&#xff1a;解锁异常&#xff1a;Redission中的"attempt to unlock lock, not locked by current thread by node id"问题分析与解决方案 在分布式系统中&#xff0c;锁是常用的同步机制&#xff0c;用于保护共享资源&#xff0c;避免并发冲突。Redission是一个…

java-多线程 2

### 7. 线程池 线程池是管理和复用线程的机制&#xff0c;可以避免频繁创建和销毁线程的开销。Java 提供了 Executor 框架来管理线程池。 #### 7.1 使用 Executors 工厂类 Executors 工厂类提供了一些静态方法&#xff0c;用于创建常见类型的线程池。 java import java.uti…

[240708] 中国 AI 企业在世界人工智能大会上展现韧性与创新

目录 中国 AI 企业在世界人工智能大会上展现韧性与创新 中国 AI 企业在世界人工智能大会上展现韧性与创新 中国科技公司在本周上海举行的世界人工智能大会上展现出强大的韧性和创新能力。超过150 种 AI 相关产品和解决方案在大会上展出&#xff0c;包括商汤科技、华为、科大讯…

电机工厂MES系统-提升生产效率与质量的关键

本文将详细介绍万界星空科技电机行业MES系统的特随着电机行业的快速发展&#xff0c;生产管理的复杂性和精细度日益提高。为了应对这一挑战&#xff0c;万界星空科技MES&#xff08;制造执行系统&#xff09;解决方案&#xff0c;为电机行业带来了前所未有的生产管理变革。点、…

Elasticsearch 分析器(Analyzer)的作用和配置

在Elasticsearch中&#xff0c;分析器&#xff08;Analyzer&#xff09;是文本处理的核心组件&#xff0c;它负责将输入的文本转换为可用于搜索和索引的词项&#xff08;tokens&#xff09;。这一过程涉及多个步骤&#xff0c;包括字符过滤、分词和标记过滤&#xff0c;共同决定…

js替换对象内部的对象名称或属性名称-(第二篇)递归

1.代码示例&#xff1a; function replaceKey(obj, oldKey, newKey) {// 如果不是对象或者oldKey不存在&#xff0c;直接返回原对象if (typeof obj ! object || !obj || !(oldKey in obj)) return obj;// 如果是数组&#xff0c;遍历数组每个元素if (Array.isArray(obj)) {obj…

laravel设计模式详解

目录 创造模式 一. 工厂方法模式 1. Eloquent ORM 模型工厂 2. 表单请求工厂 3. 服务容器中的工厂方法 二. 抽象工厂模式 1. 配置文件 2. 服务提供者 3. 门面&#xff08;Facades&#xff09; 4. 多环境配置 5. 依赖注入容器 三.原型模式 1. 配置对象的复制 2. 请…

MyBatis的底层机制

手写MyBatis底层机制 读取配置文件&#xff0c;得到数据库连接 思路 引入必要的依赖需要写一个自己的config.xml文件&#xff0c;在里面配置一些信息&#xff0c;driver&#xff0c;url &#xff0c;password&#xff0c;username需要编写Configuration类&#xff0c;对 自己…

aosp 单独grep某种类型文件,加快grep速度。

1、问题 source build/envsetup.sh lunch xxx 后可以 mgrep 可以单独搜索makefile文件 cgrep 可以单独搜索c/c文件 jgrep 可以单独搜索java文件 具体可以查看build/envsetup.sh cat build/envsetup.sh function jgrep() {find . -name .repo -prune -o -name .git -prune -o …

我“硬刚”mmkv开源库对于版本号的定义赢啦!

我“硬刚”mmkv开源库胜利啦&#xff01; 前情是这个帖子https://blog.csdn.net/jzlhll123/article/details/139917169 之前项目中将mmkv1.3.4升级到1.3.5或者1.3.6&#xff0c;就从firebase后台上看到crash。 java.lang.UnsatisfiedLinkError: dlopen failed: library “libmm…

C#面:阐述什么是依赖注入?

依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是一种设计模式&#xff0c;用于解耦组件之间的依赖关系。在传统的编程模式中&#xff0c;一个对象通常会直接创建和管理它所依赖的其他对象。而在依赖注入中&#xff0c;对象不再负责创建和管理它所依…