Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda closure type constructors

The cppreference shows that there are different rules for lambda closure type constructors.

Default Construction - Until 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.

Default Construction - Since C++14

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

Default Construction - Since 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).

Copy Assignment Operator - Until C++20

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

Copy Assignment Operator - Since 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).

What is the reason behind this change in the rules? Did standard committee identified some short comings in the standard for lambda closure type construction? If so, what are those short comings?

like image 374
cpp_enthusiast Avatar asked Apr 16 '19 12:04

cpp_enthusiast


Video Answer


1 Answers

There was a shortcoming. We couldn't use lambdas quite as "on the fly" as one might have wanted. C++20 (with the addition of allowing lambdas in unevaluated contexts) makes this code valid:

struct foo {
    int x, y;
};

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

Note how we defined the compare function inline? No need to create a named functor (could be a good idea otherwise, but we aren't forced too). And there's no need to break the declaration in two:

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

Usages like this (and many more) were the motivating factor in making this change. In the example above, the anonymous functors type will bring all the benefits a named functor type can bring. Default initialization and EBO among them.

like image 156
StoryTeller - Unslander Monica Avatar answered Oct 04 '22 11:10

StoryTeller - Unslander Monica