Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 restrictions on lambda return type

I'm reading here on cppreference about how a return type of a C++11 lambda is deduced:

if the body consists of the single return statement, the return type is the type of the returned expression (after rvalue-to-lvalue, array-to-pointer, or function-to-pointer implicit conversion)

So I think that means that a lambda can only have one return statement. But why does it work with multiple return statements still?

This compiles on both compilers:

auto f = [] (bool c1, bool c2) {
    if (c1) return 1;
    if (c2) return 2;
    else    return 3;
};
like image 655
template boy Avatar asked Nov 01 '14 20:11

template boy


People also ask

What is the return type of lambda?

The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.

What is the correct syntax for lambda expression in C++11?

Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };

Can a lambda closure be used to create a C++11 thread?

Can you create a C++11 thread with a lambda closure that takes a bunch of arguments? Yes – just like the previous case, you can pass the arguments needed by the lambda closure to the thread constructor.

Can lambda return a value C++?

Return Value A C++ lambda function executes a single expression in C++. A value may or may not be returned by this expression. It also returns function objects using a lambda.


2 Answers

That is slightly imprecise. [expr.prim.lambda]/4:

If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were (). If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

  • if the compound-statement is of the form

    { attribute-specifier-seqoptreturn expression ; }

    the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);

  • otherwise, void.

So the return type is only deduced if the whole body of the lambda expression only consists of one sole return statement.

Both GCC and Clang are not standard conforming in this case as they issue an error message if and only if two return statements lead to inconsistent deductions. This is because they already implemented the C++14 standard which deducts the return type even with multiple return statements and/or multiple other statements present. [expr.prim.lambda]/4 specifies that

The lambda return type is auto, which is replaced by the trailing-return-type if provided and/or deduced from return statements as described in 7.1.6.4.

§7.1.6.4/9

If a function with a declared return type that contains a placeholder type has multiple return statements, the return type is deduced for each return statement. If the type deduced is not the same in each deduction, the program is ill-formed.

like image 75
Columbo Avatar answered Oct 17 '22 02:10

Columbo


It works with your example because all the return statements return values of the same type. But try changing the second return to a different type, for example:

auto f = [] (bool c1, bool c2) {
    if (c1) return 1;
    if (c2) return "";
    else    return 3;
};

Compiling this with clang++ yields the following error:

main.cpp:3:13: error: return type 'const char *' must match previous return type 'int' when lambda expression has unspecified explicit
      return type
    if (c2) return "";
        ^
1 error generated.
like image 41
Steve Vinoski Avatar answered Oct 17 '22 01:10

Steve Vinoski