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.14
	q();                      // outputs 1 a 3.14
	
	auto 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)) {  // #1
	int x = h(3);
	cout << "h=" << x << endl;
}

void h(char (*)(int)) {} // #2
 
auto glambda = [](auto a) { return a; };
 
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK

int main()
{
	f1(glambda); // OK
//	auto y = f2(glambda); // error: not convertible
	h(glambda);  // OK: calls #1 since #2 is not convertible

	auto 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.mfbz.cn/a/783756.html

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

相关文章

【Spring Boot】Spring AOP动态代理,以及静态代理

目录 Spring AOP代理一. 代理的概念二. 静态代理三. JDK代理3.1 重写 invoke 方法进⾏功能增强3.2 通过Proxy类随机生成代理对象 四. CGLIB代理4.1 自定义类来重写intercept方法4.2 通过Enhancer类的create方法来创建代理类 五. AOP源码剖析 总结(重中之重&#xff0c;精华) Sp…

一款简单、免费的web文件共享服务器

#共享文件# #远程访问# #手机访问# 文件共享已成为我们日常生活和工作中不可或缺的一部分。它如同一条无形的纽带&#xff0c;将人们紧密地联系在一起&#xff0c;促进了信息的快速传播和交流。 文件共享的魅力在于其打破了地域和时间的限制。无论我们身处世界的哪个角落&…

深度解析:当下流行的人工智能大模型生成逻辑

在过去的几年里&#xff0c;人工智能领域经历了前所未有的革新&#xff0c;其中最引人注目的就是大规模预训练模型的崛起。这些模型&#xff0c;如GPT系列、BERT、T5、DALLE和CLIP等&#xff0c;凭借其强大的语言理解和生成能力&#xff0c;已经在自然语言处理&#xff08;NLP&…

Springboot使用WebSocket发送消息

1. 创建springboot项目&#xff0c;引入spring-boot-starter-websocket依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>完整项目依赖 <?xml ver…

聊聊使用GROUP_CONCAT函数遇到的坑

问题现象 在工作中我们或多或少都会使用到函数group_concat&#xff0c;它可以合并多行的某列(或多列)数据为一行&#xff0c;默认以逗号分隔。 最近碰到了一个线上bug&#xff0c;查询DB时返回的结果信息mysql自动截取了&#xff0c;导致页面显示的时候只显示了前半段结果。 …

MATLAB环境下4种噪声生成

生成噪声包括: 1)粉红色(闪烁)噪声-功率谱密度斜率-3 dB/oct。&#xff0c; - 10db /dec 2)红色(布朗)噪声-功率谱密度斜率-6 dB/oct。&#xff0c; - 20db /dec 3)蓝色噪声-功率谱密度斜率3 dB/oct。&#xff0c; 10db /dec 4)紫色(紫色)噪声-功率谱密度斜率 6db /oct。&…

抖音商城自定义小程序源码系统 前后端分离 带完整的源代码包以及搭建教程

系统概述 在当今数字化时代&#xff0c;电商平台的便捷性和个性化体验成为了吸引用户的关键。随着短视频平台的兴起&#xff0c;抖音作为其中的佼佼者&#xff0c;其商城小程序成为了商家连接消费者的新阵地。为了帮助商家快速构建个性化、高效的小程序店铺&#xff0c;本文将…

Java线程的创建·启动和休眠

一.线程的创建和启动 Java中创建线程的两种方式 ◆继承java.lang.Thread类 ◆实现java.lang.Runnable接口 ◆使用线程的步骤 继承Thread类创建线程 ◆自定义线程类继承自Thread类 ◆重写run()方法&#xff0c;编写线程执行体 ◆创建线程对象&#xff0c;调用start()方法启动…

基于大数据的电商产品评论数据分析与可视化--Python

基于大数据的电商产品评论数据分析与可视化 1绪论 1.1研究背景与意义阐述 随着电子商务领域的迅猛扩张,电商平台累积了海量的用户评价信息。这些建议不只是包含了消费者对产品的评价和经验分享,更重要的是,它们包含了丰富且价值巨大的信息。深度分析在线用户反馈不仅揭示…

#数据结构 链表

单向链表 1. 概念 单向链表 单向循环链表 双向链表 双向循环链表 解决&#xff1a;长度固定的问题&#xff0c;插入和删除麻烦的问题 1、逻辑结构&#xff1a; 线性结构 2、存储结构&#xff1a; 链式存储 链表就是将 结点 用链串起来的线性表&#xff0c;链就是 结点 中的…

《C++20设计模式》命令模式思考

文章目录 一、前言二、分析 拆解1、经典命令模式2、撤销操作3、关于Invoker类 三、实现 一、前言 哎&#xff01;只要是书上写的和经典设计模式不同&#xff0c;我就会很伤脑筋。&#x1f629; 命令模式到底是干什么的&#xff1f; 答&#xff1a;命令的发送者和接收者完全解…

环境配置05——conda创建虚拟环境指定版本torch与python

版本选择&#xff1a; python版本3.11.8torch版本2.1.2 1.创建环境 conda create -n t212p311 python3.11.8 2.下载torch pytorch-wheels-cu121安装包下载_开源镜像站-阿里云 3. 安装torch 进入虚拟环境 activate t212p311 进入torch安装包所在目录&#xff0c;安装torc…

html+css+js随机验证码

随机画入字符、线条 源代码在图片后面 点赞❤️关注&#x1f60d;收藏⭐️ 互粉必回 图示 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"…

将QComboBox下拉项中的文本居中、居右

目录 1. 需求提出 2. 解决方法 1. 需求提出 QComboBox下拉项中的文本默认是居左的&#xff0c;如下&#xff1a; 有时需要将下拉项中的文本居中、居右。如何实现&#xff1f; 2. 解决方法 首先想到的是通过样式表来解决&#xff0c;但找遍Qt Assist和网络&#xff0c;都没这…

MySQL存储与优化 一、MySQL架构原理

1.MySQL体系架构 MySQL Server架构自顶向下大致可以分网络连接层、服务层、存储引擎层和系统文件层 (1)网络连接层 客户端连接器&#xff08;Client Connectors&#xff09;&#xff1a;提供与MySQL服务器建立的支持。目前几乎支持所有主流的服务端编程技术&#xff0c;例如常…

EE trade:市价建仓的优缺点是什么

在金融市场的复杂环境中&#xff0c;市价建仓策略作为一种常见的交易手段&#xff0c;其优缺点成为了投资者关注的焦点。通过深入分析&#xff0c;我们可以更全面地理解这一策略的利弊&#xff0c;从而在实际操作中做出更加明智的决策。 市价建仓优点分析 快速执行 市价建仓…

鸿蒙系统:未来智能生态的引领者

在当今这个日新月异的互联网领域&#xff0c;操作系统作为连接硬件与软件的桥梁&#xff0c;其重要性不言而喻。随着华为鸿蒙系统&#xff08;HarmonyOS&#xff09;的崛起&#xff0c;一场关于操作系统未来的讨论再次被推向高潮。 鸿蒙OS&#xff0c;华为的全新力作&#xff…

从nginx返回404来看http1.0和http1.1的区别

序言 什么样的人可以称之为有智慧的人呢&#xff1f;如果下一个定义&#xff0c;你会如何来定义&#xff1f; 所谓智慧&#xff0c;就是能区分自己能改变的部分&#xff0c;自己无法改变的部分&#xff0c;努力去做自己能改变的&#xff0c;而不要天天想着那些无法改变的东西&a…

2024年电脑监控软件排行榜(真实测评推荐七款电脑监控软件)

在信息化快速发展的今天&#xff0c;企业对员工电脑活动的监控变得尤为重要。有效的电脑监控软件不仅可以提升员工的工作效率&#xff0c;还能防止信息泄露&#xff0c;保障企业的数据安全。本文将介绍几款知名的电脑监控软件&#xff0c;并对其特点进行详细分析&#xff0c;帮…

JavaWeb系列二十三: web 应用常用功能(文件上传下载)

文章目录 5. 文件上传基本介绍5.1 文件上传-原理示意图5.2 文件上传页面5.3 走通Servlet5.4 表单项区别处理5.5 创建目录-保存文件5.6 中文编码问题5.7 文件上传注意事项和细节5.7.1 按照年月日目录存放5.7.2 文件覆盖问题5.7.3 封装一下 5.8 文件上传其他注意事项5.8.1 upload…