Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing generalize-captured objects in lambda trailing return type

int main()
{
    auto l = [x = 10]() -> decltype(x) {};
}   
  • clang++ 4.0 rejects this code with the following error:

    error: use of undeclared identifier 'x'
            auto l = [x = 10]() -> decltype(x) {};
                                            ^
    
  • g++ 7 rejects this code with the following error:

    In function 'int main()':
    error: 'x' was not declared in this scope
      auto l = [x = 10]() -> decltype(x) {};
                                      ^
    error: 'x' was not declared in this scope
    In lambda function:
    warning: no return statement in function returning non-void [-Wreturn-type]
      auto l = [x = 10]() -> decltype(x) {};
                                      ^
    

Is this a bug or is there something in the standard that explicitly prevents objects captured with the C++14 generalized syntax from being used in the lambda's trailing return type?


Note that both compilers are happy with non-generalized captures:

int main()
{
    int x = 10;
    auto l = [x]() -> decltype(x) { return 0; };
}   
like image 561
Vittorio Romeo Avatar asked Dec 15 '16 10:12

Vittorio Romeo


1 Answers

TL;DR: Compilers behave as expected.

The standard defines lambda semantics as follows [expr.prim.lambda, section 1]:

lambda-expression:

   lambda-introducer lambda-declarator_opt compound-statement

Here compound-statement is just the body of lambda between {}, because everything else is included in lambda-declarator:

lambda-declarator:

   ( parameter-declaration-clause ) decl-specifier-seq_opt
       exception-specification_opt attribute-specifier-seq_opt trailing-return-type_opt

Also, in section 12 of the same chapter, it's said that

An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression’s compound-statement, except that:

(12.1) — if the capture is by copy (see below), the non-static data member declared for the capture and the variable are treated as two different ways of referring to the same object, which has the lifetime of the non-static data member, and no additional copy and destruction is performed, and

(12.2) — if the capture is by reference, the variable’s lifetime ends when the closure object’s lifetime ends.

So, in your first example, variable x scope is the lambda body only, not including the decltype expression. In the second example, obviously, x scope is the function main.

like image 158
alexeykuzmin0 Avatar answered Nov 05 '22 03:11

alexeykuzmin0