My book says this:
Lambdas with function bodies that contain anything other than a single return statement that do not specify a return type return void.
but this:
auto f = []{
int i=0; i++;
return std::string("foo");
};
std::cout << f() << std::endl;
actually compiles and prints out "foo", but that lambda expr has more than just a single return statement so it should return void, because it does not manually specify "-> std::string" as a return type.
What's going on here?
I'm using Apple's compiler in the latest Xcode 4.6, based on Clang 3.2 it seems:
clang --version
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix
The book accurately reflects the rules in draft n3290 of the Standard. Perhaps your compiler implemented a different draft.
In section 5.1.2p4, the draft reads
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, array-to-pointer conversion, and function-to-pointer conversion;
- otherwise, void.
The syntactic construct attribute-specifier-seq may be alignas
or the double-bracketed attributes. Not variable declarations.
Draft n3485, which followed publication of C++11 (i.e. it is work in progress toward C++1y), contains the same wording. I don't know if there was a different rule in some draft earlier than n3290.
If you use popular compilers (gcc, Visual Studio), you usually don't need to specify return type as long as the compiler is able to determine it unambiguously - like in your example.
The following example shows a lambda, which requires explicit return type information:
auto lambda = [](bool b) -> float
{
if (b)
return 5.0f;
else
return 6.0;
};
I asked Bjarne Stroustrup regarding this matter, his comment:
I do not know if C++11 allows the deduction of the return type is there are several return statements with identical return type. If not, that's planned for C++14.
I am not sure of what to make from the quote in the question, but here is what the C++11 standard says about lambdas without declarator or return type:
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 (5.1.2p4):
— 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.
Clang implements the proposed resolution to C++ core issue 975. That allows an arbitrary body for a lambda, with any number of return statements, and deduces the return value from the returned expression under the proviso that they must all produce the same type.
In C++14, this support is generalized further by N3638, which was voted into the working draft for the standard at the Bristol meeting of WG21.
Draft n3485 indicates that if the compiler can unambiguously determine the return type it will allow for the lambda to not specify it.