Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSVC behaves different about default constructor of closure type in C++20

The standard says

The closure type associated with a lambda-expression has no default constructor if the lambda-expression has a lambda-capture and a defaulted default constructor otherwise. It has a deleted copy assignment operator if the lambda-expression has a lambda-capture and defaulted copy and move assignment operators otherwise. It has a defaulted copy constructor and a defaulted move constructor (15.8). [ Note: These special member functions are implicitly defined as usual, and might therefore be defined as deleted. — end note ]

Cppreference specifically says that (emphasis mine)

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).

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).

So the following must be valid.

auto lambda = [&](){};

static_assert(!std::is_default_constructible<decltype(lambda)>::value);
static_assert(!std::is_assignable<decltype(lambda), decltype(lambda)>::value);

But MSVC says they are default_constructible, etc.

https://godbolt.org/z/E6EW3rMcE

Since the paper didn't specifically mention about capture-default but not capturing in actual, I wonder if this is MSVC defect or allowed to be implementation-defined.


Update

I've reported this bug to Microsoft, and it will be fixed on the coming release link.

like image 574
김선달 Avatar asked Jul 13 '21 13:07

김선달


People also ask

How many types of constructors are there in C #?

In this article, we will learn about constructors and types of constructors in C#. There are five different types of constructors in C#. To create a constructor, we use the shortcut key ctor tab twice. It will create a respective class constructor. A constructor is used for creating objects of a class. Following is the list of constructors in C#.

What is this warning about the default constructor transparency in Silverlight?

This warning is only applied to code that is running the CoreCLR (the version of the CLR that is specific to Silverlight web applications). The transparency attribute of the default constructor of a derived class is not as critical as the transparency of the base class.

What is copy constructor in C++?

The constructor which creates an object by copying variables from another object is called a copy constructor. The purpose of a copy constructor is to initialize a new instance to the values of an existing instance. The copy constructor is invoked by instantiating an object of type employee and passing it the object to be copied.

What is the difference between default constructor and parametrized constructor?

A constructor without any parameters is called a default constructor. If we do not create constructor the class will automatically call default constructor when an object is created. A constructor with at least one parameter is called a parametrized constructor.


1 Answers

The standard is pretty clear here. In [expr.prim.lambda.closure]/13:

The closure type associated with a lambda-expression has no default constructor if the lambda-expression has a lambda-capture and a defaulted default constructor otherwise.

This rule is based on the lexical makeup of the lambda, not the semantic analysis that we do to decide if there is anything captured. It is a grammatical distinction.

If a lambda starts with [], then it has no lambda-capture, and thus has a defaulted default constructor.

If a lambda starts with [&], then it has a lambda-capture, and thus has no default constructor - regardless of whether anything is captured. It doesn't matter if anything is captured or not.

The clarification that cppreference adds here is correct, and helpful. The lambda [&](){} is not default constructible (or, by the same logic, assignable). So, yes this is a MSVC bug.


Note that this is the same kind of rule that we have to determine if a lambda can be converted to a function pointer: whether or not there is a lambda-capture, not whether or not there is any capture. Thus, [](){} is convertible to void(*)() but [&](){} is not.

like image 66
Barry Avatar answered Oct 15 '22 14:10

Barry