Lambda 闭包类型构造函数

Lambda closure type constructors

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

默认构造 - 直到 C++14

ClosureType() = delete; (until C++14)

Closure types are not Default Constructible. Closure types have a deleted (until C++14)no (since C++14) default constructor.

默认构造 - 自 C++14

Closure types have no (since C++14) default constructor.

默认构造 - 自 C++20

If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).

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

The copy assignment operator is defined as deleted (and the move assignment operator is not declared). Closure types are not CopyAssignable.

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

If no captures are specified, the closure type has a defaulted copy assignment operator and a defaulted move assignment operator. Otherwise, it has a deleted copy assignment operator (this includes the case when there is a capture-default, even if it does not actually capture anything).

这种规则变化背后的原因是什么?标准委员会是否发现了 lambda 封闭式结构标准中的一些缺点?如果有,那些缺点是什么?

有个缺点。我们不能像人们希望的那样 "on the fly" 使用 lambda。 C++20(加上允许在未计算的上下文中使用 lambda)使此代码有效:

struct foo {
    int x, y;
};

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

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

// 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。