When can we omit the return type in a C++11 lambda?
Asked Answered
N

3

17

As far as I know, in standard C++11 (not C++14), when omitting the return type of a lambda, its return type is deduced to be:

  1. The type of the returned expression, whenever the lambda consists of nothing but a single return statement with an expression, or
  2. void in all other cases.

Consider now this code:

#include <iostream>

auto closure = [](int x)
{
    x++;
    return x;
};

int main()
{
    int y = closure(10);
    std::cout << y << std::endl;
}

This should fall under case 2., however the code compiles as if were C++14 with auto type deduction, in both g++4.9.2, g++5 and clang++, with -pedantic -Wall -Wextra -std=c++11. What's going on here? Am I interpreting the standard wrong?

Nisa answered 10/3, 2015 at 3:5 Comment(0)
E
15

Your code is being accepted without any warnings because the original C++11 restriction is considered a defect in the standard, which allows implementations to fix the behavior. See CWG DR975, DR1048 and N3638.

975. Restrictions on return type deduction for lambdas

[Moved to DR status at the April, 2013 meeting as part of paper N3638.]

There does not appear to be any technical difficulty that would require the current restriction that the return type of a lambda can be deduced only if the body of the lambda consists of a single return statement. In particular, multiple return statements could be permitted if they all return the same type.

1048. auto deduction and lambda return type deduction.

...

Notes from the November, 2014 meeting:

CWG agreed that the change embodied in paper N3638 should be considered to have been a DR against C++11.

In summary, DR975 proposed modifying the rules for return type deduction for lambda expressions to allow multiple return statements.

DR1048 identifies a discrepancy where the rules for deducing the return type for normal functions using the placeholder type auto differs slightly from the rules proposed in DR975. Specifically, return type deduction for normal functions would discard top-level cv-qualifiers in all cases, where as those for lambda expressions would preserve cv-qualifiers for class types.

N3638 resolves this issue, amongst others.


I doubt there's any way to revert to the original behavior short of finding a compiler version that shipped with C++11 lambda support prior to the implementation of the DR above.

Eschar answered 10/3, 2015 at 3:44 Comment(4)
I am still a bit confused. Can the body of lambda consists of multiple statements but only one return statement, or its entire body must consists of only one return statement to apply my case 1.?Nisa
Actually, that proposed resolution wasn't adopted. Instead, N3638 was, and then DR1048 clarified that the N3638 changes for lambdas should be considered a DR against C++11.And
@And Right below the DR I linked to :S, should've kept reading. Thank you.Eschar
@Nisa I got rid of the text I added in my first edit because the answer was getting unnecessarily long quoting the DRs, but multiple return statements are absolutely allowed, not just multiple statements culminating in a single return statement.Eschar
M
5

Some C++14 rules are available in C++11 mode, when the compiler writers considered it too complicated to implement both rules at once.

Maisel answered 10/3, 2015 at 3:28 Comment(4)
So, theoretically, my code is not 100% C++11 compliant, right?Nisa
Yes, it looks like that wouldn't be accepted in C++11.Maisel
I think you can use comma operator to make it a single statement, then it'll be C++11 compliantTitania
@LưuVĩnhPhúc the problem is that I have some code in which the lambda has significantly more statements, and my code compiled fine (with no warnings at maximum warning level + pedantic) without specifying the return type explicitly.Nisa
G
2

This is what I find in the C++ Draft Standard N3337:

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-seqopt return 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.

[ Example:

auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a
                                  // braced-init-list is not an expression)

end example ]

The standard seems to indicate that:

  • When only one statement is present, and
  • It is a return statement, and
  • The object being returned is an expression

Then the return type is deduced from the expression. Otherwise the return type is void.

Giliana answered 10/3, 2015 at 3:44 Comment(1)
yes, so it seems that the body of the lambda should only consist of return something;Nisa

© 2022 - 2024 — McMap. All rights reserved.