13

Consider the following program:

#include <iostream>
struct X {
  X () = default;
  X (X &) { std::cout << "non-const called" << std::endl; }
  X (X const &) { std::cout << "const called" << std::endl; }
  int i () const { return 7; }
};

auto f () {
  X x;
  auto lambda = [=]() { return x.i(); };
  return lambda;
}

int main()
{
  auto lambda = f();
  std::cout << lambda () << std::endl;
  return 0;
}

With VC++15, I get the output

const called
const called
7

With Clang 3.9, I get

non-const called
7

Which compiler is correct here?

JohnB
  • 13,315
  • 4
  • 38
  • 65
  • 1
    [This](http://stackoverflow.com/questions/3772867/lambda-capture-as-const-reference) may be of your interest. To be straight I don't think your question is a duplicate :) – W.F. Dec 03 '16 at 17:07
  • It's worth noting that with optimizations enabled, VC also applies RVO resulting in only one call to `X(X const&)`. – Oktalist Dec 03 '16 at 23:40
  • @skypjack: Are you sure lambdas construct a const member? http://ideone.com/RQ7OjC I think the data members are not necessarily const, only `operator ()` is. – JohnB Dec 04 '16 at 03:12
  • @JohnB Fair enough. I'm correcting the answer too. Good catch. – skypjack Dec 04 '16 at 07:54
  • @Oktalist still the call should be to `X(X &)`, right? – skypjack Dec 04 '16 at 08:05
  • @skypjack As far as I know, right. – Oktalist Dec 04 '16 at 15:09

1 Answers1

2

I would say that clang is right.
The most suited constructor is called only once when the lambda captures x and the constructor for the returned value is optimized out.
That's why you obtain only one non-const called.


See here and here for further details about copy-elision and RVO.

skypjack
  • 49,335
  • 19
  • 95
  • 187