c++c++11gccclanggcc4.8

Why this code fails to compile with gcc 4.8.5 while it compiles fine with clang


#include<iostream>                                                                                                                                    

using namespace std;                                                                                                                                  

int main()                                                                                                                                            
{                                                                                                                                                     
   const int k = 10;                                                                                                                                  

   // Capture k by value                                                                                                                              
   auto myl = [k] (int k) { cout << " ++k=" << ++k ; };                                                                                            

   myl(k+10);                                                                                                                                             
}  

Error below

lamda.cpp: In lambda function:
lamda.cpp:10:50: error: increment of read-only variable âkâ
    auto myl = [k] (int k) { cout << " ++K=" << ++k ; };

clearly what I am referring to is local variable K and not const member K.


Solution

  • This isn't quite as straightforward as it might seem. A lambda that captures k by copy is mostly equivalent to a struct object whose closure type has a member named k, and with an operator() whose definition uses the specified parameters and body. If that were technically true, sure, we know that a function parameter hides a class member.

    Except that's not how the Standard actually defines lambdas. Instead, it says that any entity captured by value corresponds to an unnamed member of the closure type. In the lambda body, name lookup looks in the lambda's enclosing scope, not the scope of the closure type. If that name lookup finds an entity captured by copy, the compiler must internally transform that usage of the name to a usage of the unnamed member instead. In C++11 and C++14, these rules didn't clearly specify how lambda parameter names fit into that name lookup scheme, and as a result, different compilers and compiler versions didn't agree on behavior in cases like this where a captured entity and a lambda parameter had the same name.

    With Defect Resolution 2211, C++17 solved the issue by just making it illegal:

    [expr.prim.lambda.capture]/5:

    If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator's parameter-declaration-clause, the program is ill-formed. [ Example:

    void f() {
      int x = 0;
      auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
    }
    

    -- end example ]

    (See also the same paragraph in the current draft mirror.)