Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++17 lambda captures with relaxed type requirements

I have got a following code, that does compile with C++17 compiler but will not with C++14. I am wondering what was the change, that allowed following code to compile:

struct Foo{
  Foo()=default;
  Foo(const Foo&)=default;// copy by const ref 
};

struct Bar{
  Bar()=default;  
  Bar(Bar&)=default; //copy by non const
};

int main()
{
  Foo foo;
  Bar bar;
  Bar barcpy = bar;
  auto foolam = [foo]{};
  auto barlam = [bar]{}; //compiles only with C++17
}

Is there any exact proposal for this code to compile or it is by the way of some other feature?

like image 727
Dawid Pilarski Avatar asked Mar 19 '19 16:03

Dawid Pilarski


1 Answers

Guaranteed Copy Elision (with wording). The lambda here is actually a red herring.

In C++14, this:

auto barlam = [bar]{};

still requires move-construction to be valid (even if you don't want the move and the move is likely to be elided anyway). But that lambda isn't move-constructible, because Bar isn't move-constructible. Foo is move-constructible, so foolam works fine.

A non-lambda version of this would be:

auto bar = Bar{}; // error in C++14
auto foo = Foo{}; // ok

In C++17, this isn't move construction - we just directly initialize the target object. In one sense, we're eliding the move. In a difference sense, there actually is no move by the language rules at all. So this:

auto bar = Bar{};

is exactly equivalent to:

Bar bar{};

The same holds for the lambda.

like image 143
Barry Avatar answered Oct 21 '22 04:10

Barry