auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
clang++ 3.6.0 and newer print out "You're using clang++!" and warn about the capture
foo
being unused.g++ 4.9.0 and newer print out "You're using g++!" and warn about the parameter
foo
being unused.
What compiler is more accurately following the C++ Standard here?
I'm trying to pack together a few comments to the question to give you a meaningful answer.
First of all, note that:
foo
Therefore the logic would make me say at a first glance that the parameter should shadow the captured variable as if in:
Anyway, @n.m. correctly noted that the non-static data members declared for copy-captured variables are actually unnamed. That being said, the unnamed data member is still accessed by means of an identifier (that is
foo
). Therefore, the parameter name of the function call operator should still (let me say) shadow that identifier.As correctly pointed out by @n.m. in the comments to the question:
Because of that, I'd say that clang is right.
Update: as promised by the Core chair in the bottom quote, the code is now ill-formed:
There were a few issues concerning name lookup in lambdas a while ago. They were resolved by N2927:
Lookup is always done in the context of the lambda-expression, never "after" the transformation to a closure type's member function body. See [expr.prim.lambda]/8:
(The example also makes clear that lookup does not somehow consider the generated capture member of the closure type.)
The name
foo
is not (re)declared in the capture; it is declared in the block enclosing the lambda expression. The parameterfoo
is declared in a block that is nested in that outer block (see [basic.scope.block]/2, which also explicitly mentions lambda parameters). The order of lookup is clearly from inner to outer blocks. Hence the parameter should be selected, that is, Clang is right.If you were to make the capture an init-capture, i.e.
foo = ""
instead offoo
, the answer would not be clear. This is because the capture now actually induces a declaration whose "block" is not given. I messaged the core chair on this, who replied