【问题标题】:Lambda closure type constructorsLambda 闭包类型构造函数
【发布时间】:2019-09-06 13:22:06
【问题描述】:

cppreference 表明 lambda 闭包类型构造函数有不同的规则。

默认构造 - 直到 C++14

ClosureType() = 删除; (直到 C++14)

闭包类型不是默认可构造的。闭包类型有 删除(C++14 前)无(C++​​14 起)默认构造函数。

默认构造 - 自 C++14 起

闭包类型没有(C++14 起)默认构造函数。

默认构造 - 从 C++20 开始

如果没有指定捕获,闭包类型有一个默认的默认值 构造函数。否则,它没有默认构造函数(这包括 存在默认捕获的情况,即使它实际上没有 捕捉任何东西)。

复制赋值运算符 - 直到 C++20

复制赋值运算符被定义为删除(和移动 未声明赋值运算符)。闭包类型不是 可复制。

复制赋值运算符 - 自 C++20 起

如果未指定捕获,则闭包类型具有默认副本 赋值运算符和默认的移动赋值运算符。 否则,它有一个已删除的复制赋值运算符(这包括 存在默认捕获的情况,即使它实际上没有 捕捉任何东西)。

此次规则变更背后的原因是什么?标准委员会是否发现了 lambda 封闭式结构标准中的一些不足之处?如果是这样,这些缺点是什么?

【问题讨论】:

标签: c++ c++11 lambda c++20


【解决方案1】:

有一个缺点。我们不能像人们想要的那样“即时”使用 lambdas。 C++20(在未评估的上下文中添加了允许 lambda)使此代码有效:

struct foo {
    int x, y;
};

std::map<foo, decltype([](foo const& a, foo const& b) { return a.x < a.y; })> m;

注意我们是如何定义内联比较函数的?无需创建命名仿函数(否则可能是个好主意,但我们也不是强制)。而且没有必要将声明一分为二:

// C++17
auto cmp = [](foo const& a, foo const& b) { return a.x < a.y; };
std::map<foo, decltype(cmp)> m(cmp); // And also need to pass and hold it!

像这样(以及更多)的用法是做出这种改变的激励因素。在上面的示例中,匿名函子类型将带来命名函子类型可以带来的所有好处。其中默认初始化和EBO。

【讨论】:

  • FWIW,C++20 现在允许std::map&lt;foo, decltype(cmp)&gt; m;
  • 所以,在 C++20 之前的 lambda 闭包类型构造期间,没有/删除默认构造函数基本上是一个缺点。我的理解正确吗?
  • @AImx1 - 您需要将compare 作为参数传递给构造函数。在初始化列表之后传递它:test ({ "BS", "CA", "PR", "US" }, compare); - 这就是在 C++20 之前需要这样做的方式。
  • @AImx1 - 注意。 lambda 表达式是一项新功能,并不是其行为的所有方面都一开始就很清楚。随着用户和编译器编写者使用它的经验的增长,委员会回来并重新评估以前被禁止的功能。如果您遵循标准化流程,您会开始注意到这是一个反复出现的主题。当我们不确定时,最好禁用某些东西。因为它可能在未来总是被启用:)
  • @StoryTeller 这很有意义。谢谢你的解释。
猜你喜欢
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多