无捕获 lambda 是结构类型吗?

2024-05-27

P1907R1 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1907r1.html,接受 C++20,引入结构类型,它们是非类型模板参数的有效类型。

GCC 和 Clang 都接受以下 C++2a 代码片段:

template<auto v>
constexpr auto identity_v = v;

constexpr auto l1 = [](){};
constexpr auto l2 = identity_v<l1>; 

这意味着无捕获 lambda 的类型是结构类型。

Question

  • 无捕获 lambda 是否确实满足其类型成为结构类型的要求?

All standard references below, unless explicitly noted otherwise, refers to N4861 (March 2020 post-Prague working draft/C++20 DIS) https://timsong-cpp.github.io/cppwp/n4861/.


无捕获 lambda 的类型(其闭合类型) is a 结构类型

从今以后,我们将 lambda 的类型单独称为闭合类型.

正如下面的标准段落所示,无捕获 lambda 的闭包类型:

  • 满足其成为一个的要求文字(类)类型,而且此外
  • 满足文字类型的要求,使其成为结构类型,

因此可以用作非类型模板参数的类型,使得示例片段

template<auto v>
constexpr auto identity_v = v;

constexpr auto l1 = [](){};
constexpr auto l2 = identity_v<l1>;

确实是格式良好的。


lambda 的闭包类型是非联合类类型

受以下管辖[expr.prim.lambda.closure]/1 https://timsong-cpp.github.io/cppwp/n4861/expr.prim.lambda.closure#1 [emphasis mine]

的类型lambda 表达式(这也是闭包对象的类型)是唯一的、未命名的非联合类类型,称为闭包类型,其属性如下所述。

闭合类型是非联合类类型.


无捕获 lambda 的闭包类型是文字(类)类型

受以下管辖[基本类型]/10 https://timsong-cpp.github.io/cppwp/n4861/basic.types#10[提炼,emphasis mine]

类型是一个文字类型如果是:

  • [...]
  • a possibly cv-qualified class type that has all of the following properties:
    • 它有一个 constexpr 析构函数([dcl.constexpr]),
    • it is either 闭合类型([expr.prim.lambda.closure])、聚合类型 ([dcl.init.aggr]),或至少有一个 constexpr 构造函数或构造函数模板(可能从基类继承 类)不是复制或移动构造函数,
    • 如果它是联合体,则其至少一个非静态数据成员是非易失性文字类型,并且
    • 如果它不是联合,则其所有非静态数据成员和基类都是非易失性文字类型。

闭包类型是文字类型如果

  • 有一个 constexpr 析构函数,并且如果
  • 它的所有非静态数据成员都是非易失性文字类型。

无捕获 lambda 的闭包类型没有非静态数据成员,因此满足后一个要求。前者怎么样,constexpr 析构函数?

隐式生成的 constexpr 析构函数

受以下管辖[expr.prim.lambda.closure]/14 https://timsong-cpp.github.io/cppwp/n4861/expr.prim.lambda.closure#14

与 a 关联的闭包类型lambda 表达式有一个隐式声明的析构函数([class.dtor])。

闭包类型的析构函数是隐式声明的。此外,[/dcl.fct.def.default]/5 https://timsong-cpp.github.io/cppwp/n4861/dcl.fct.def.default#5描述[摘录,emphasis mine]

显式默认函数和隐式声明函数统称为违约功能,以及实施应为它们提供隐式定义([class.ctor],[类.dtor], [class.copy.ctor], [class.copy.assign]), [...]

即集体术语违约函数还包括隐式声明的析构函数。

最后,[class.dtor]/9 https://timsong-cpp.github.io/cppwp/n4861/class.dtor#9

如果默认析构函数满足 constexpr 析构函数 ([dcl.constexpr]) 的要求,则它是 constexpr 析构函数。

描述默认析构函数是 constexpr 析构函数,如果它们满足以下要求[dcl.constexpr] https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr, 特别[dcl.constexpr]/3 https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#3 and [dcl.constexpr]/5 https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#5[摘录,emphasis mine]

[dcl.constexpr]/3constexpr 函数的定义应满足以下要求:

  • [...]
  • 如果函数是构造函数或析构函数,其类不得有任何虚拟基类;
  • [...]

[dcl.constexpr]/5constexpr 析构函数的定义,其函数体 is not = delete还应满足以下要求:

  • 对于类类型或其(可能是多维)数组的每个子对象,该类类型应具有 constexpr 析构函数。

所有这些都满足无捕获 lambda 的闭包类型(没有基类,也没有子对象;请参阅[介绍对象]/2 https://timsong-cpp.github.io/cppwp/n4861/intro.object#2对于后者)。

因此,无捕获 lambda 的闭包类型是文字类型。


无捕获 lambda 的闭包类型是结构类型

As per [温度参数]/6 https://timsong-cpp.github.io/cppwp/n4861/temp.param#6 and [温度参数]/7 https://timsong-cpp.github.io/cppwp/n4861/temp.param#7[提炼,emphasis mine]

[温度参数]/6非类型模板参数应具有以下类型之一(可能是 cv 限定的):

  • 结构类型(见下文),
  • [...]

[温度参数]/7

A 结构类型是以下之一:

  • 标量类型,或
  • 左值引用类型,或者
  • a literal class type with the following properties:
    • 所有基类和非静态数据成员都是公共且不可变的
    • 所有基类和非静态数据成员的类型都是结构类型或其(可能是多维)数组。

如果文字类类型没有基类和非静态数据成员,那么它就是一种结构类型。这两者都适用于无捕获 lambda,因此,无捕获 lambda 的闭包类型是结构类型。


关于原文的一些注释intent允许 lambda 的闭包类型为文字类型

N4487 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4487.pdf提议允许某些 lambda 表达式和某些闭包对象上的操作出现在常量表达式中,并包含一个专门的部分来讨论闭包类型是文字类型的主题:

如果闭包对象的每个数据成员的类型都是文字类型,则该闭包对象应该是文字类型。

C++14 中的闭包类型永远不可能是文字类型 – 即使它的所有 数据成员是文字类型——因为它缺少 constexpr 不是复制或移动构造函数的构造函数。如果这样的关闭 类型被允许有一个隐式定义的默认构造函数 将是 constexpr,使其成为文字类型。但是,因为关闭 根据定义,类型必须删除其默认构造函数, 禁止实现隐式定义一个。 [...]

P0170R1 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0170r1.pdf包含 N4487 的核心措辞,已被 C++17 接受并实现。

然而,此时(C++14 和 C++17)析构函数不能是 constexpr,因此自然不要求文字类型具有 constexpr 析构函数;[基本类型]/10.5.1 https://timsong-cpp.github.io/cppwp/n4140/basic.types#10.5.1在 N4140 (C++14) 以及[基本类型]/10.5.1 https://timsong-cpp.github.io/cppwp/n4659/basic.types#10.5.1在 N4659 (C++17) 中,要求析构函数很简单:

如果某个类型满足以下条件,则该类型是文字类型:

  • [...]
  • a class type (Clause [class]) that has all of the following properties:
    • 它有一个简单的析构函数,
    • [...]

P1907R1 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1907r1.html,为 C++20 所接受,扩展了以下要求模板参数对象不断的破坏;[温度参数]/8 https://timsong-cpp.github.io/cppwp/n4861/temp.param#8 [emphasis mine]:

An id-表达式命名非类型模板参数类别类型T表示类型的静态存储持续时间对象const T,称为模板参数对象,其值是相应模板参数转换为类型后的值模板参数。程序中所有此类相同类型、相同值的模板参数都表示同一个模板参数对象。 [...]模板参数对象应不断销毁。

and, P0784R7 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0784r7.html,也被 C++20 接受,特别包含 constexpr 销毁的引入,包括更新类型为文字类型的要求;在论文的早期版本中特别描述,P0784R1 http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0784r1.html:

constexpr 析构函数的建议规则是:

  • [...]
  • 文字类型需要 constexpr 析构函数(之前,对平凡析构函数提出了更强的要求)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无捕获 lambda 是结构类型吗? 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐