Why does [=]{} have a lambda capture? - c++

At an intuitive level, it makes sense that a lambda that needs to carry no state (through a reference or otherwise) should be cleanly convertible to a naked function pointer. However, I was recently surprised to see the following failing in GCC, Clang, and MSVC:
int main(int, char *[]) {
void (*fp)() = []{}; // OK
//fp = [=]{}; // XXX - no user defined conversion operator available
//fp = [&]{}; // XXX - same ...
}
The C++17 spec (or at least visible public draft version N4713), refers in item 7 of § 8.4.5.1 [expr.prim.lambda.closure] to lambdas with and without captures:
The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (10.5) having the same parameter and return types as the closure type’s function call operator. ...
However, looking into the formal grammar you can see the following in § 8.4.5 [expr.prim.lambda]:
lambda-expression :
lambda-introducer compound-statement
...
lambda-introducer :
[ lambda-captureopt ]
...
and in § 8.4.5.2 [expr.prim.lambda.capture]:
lambda-capture :
capture-default
capture-list
capture-default, capture-list
capture-default :
&
=
So all the compilers were actually obeying the letter of the law to my dismay...
Why does the language define the existence of a capture as a narrow grammatical distinction in the declaration instead of basing it on whether the body contains references to any non-static/captured state?

The change that allowed the conversion was initiated by a national body comment. See n3052: Converting Lambdas to Function Pointers which refers to national body comment UK 42:
A lambda with an empty capture list has identical semantics to a regular function type. By requiring this mapping we get an efficient lambda type with a known API that is also compatible with existing operating system and C library functions.
and the resolution from N3052 was:
Resolution: Add a new paragraph: "A lambda expression with an empty capture set shall be convertible to pointer to function type R(P), where R is the return type and P is the parameter-type-list of the lambda expression." Additionally it might be good to (a) allow conversion to function reference and (b) allow extern "C" function pointer types.
...
Add a new paragraph after paragraph 5. The intent of this edit is to obtain a closure-to-function-pointer conversion for a lambda with no lambda-capture.
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type's function call operator.
and that is where we are today. Note the comment said empty capture list and what we have today seems to match the intent as worded in the comment.
It looks like it was a fix based on a national body comment and was applied narrowly.

The rule you propose would be extremely fragile, especially in the pre-P0588R1 world when implicit captures depended on odr-use.
Consider:
void g(int);
void h(const int&);
int my_min(int, int);
void f(int i) {
const int x = 1, y = i;
[=]{ g(x); }; // no capture, can convert?
[=]{ g(y); }; // captures y
[=]{ h(x); }; // captures x
[=]{ my_min(x, 0); }; // no capture, can convert?
[=]{ std::min(x, 0); }; // captures x
}

Related

How can I replace the auto keyword in this code?

I am following this tutorial. The following declaration found in main.cc has me intrigued:
auto say_hello = [](const HttpRequest& request) -> HttpResponse {
HttpResponse response(HttpStatusCode::Ok);
response.SetHeader("Content-Type", "text/plain");
response.SetContent("Hello, world\n");
return response;
}
This is shown in the debugging window.
I wish to replace the auto keyword with the original data type. I have tried the following but it fails:
HttpResponse say_hello = [](const HttpRequest& request) -> HttpResponse {...}
Could someone tell me why it is wrong? What is the correct solution? Thank you so much!!!
I think it's important to know the 3 following methods when working with lambdas.
The three firsts do essentially the same thing: storing the lambda for future use.
The other seems to be what you expect from your code: you directly call the lambda and get the result, so the return type is the type returned by the lambda.
#include <iostream>
#include <functional>
int main()
{
// Auto store the lambda
auto auto_keyword = [](int a) -> int
{ return a; };
std::cout << auto_keyword(42) << std::endl;
// std::function store the lambda
std::function<int(int)> std_function = [](int a) -> int
{ return a; };
std::cout << std_function(42) << std::endl;
// raw function pointer
int (*raw_fptr)(int) = [](int a) -> int
{ return a; };
std::cout << raw_fptr(42) << std::endl;
// direct call to the lambda. (what you expect from your question)
std::cout << ([](int a) -> int{ return a; })(42) << std::endl;
return 0;
}
A lot of things happen here, and I suggest you to read at least this page from the reference for a better understanding.
According to cppreference, (emphasize mine)
The lambda expression is a prvalue expression of unique unnamed non-union non-aggregate class type, known as closure type
As the type of a lambda expression is an unnamed type you cannot use it in a declaration. That is the reason why auto is the common usage for a lambda.
If you want to be more explicit for the arguments and return type, you can store the lambda in a std::function variable:
std::function<HttpResponse(const HttpRequest&)> say_hello = ...
But std::function is still not really the type of the lambda (which is unnamed...), it is just the type of a variable which is able to hold that lambda, as it could old the address of a plain function.
For further reference, draft n4860 for C++20 says at 7.5.5.1 Closure types [expr.prim.lambda.closure] §1
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union
class type, called the closure type ...
From C++ standard
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the
type of the closure object) is a unique, unnamed non-union class type
— called the closure type — whose properties are described below. This
class type is not an aggregate (8.5.1). The closure type is declared
in the smallest block scope, class scope, or namespace scope that
contains the corresponding lambda-expression.
In short each instance of a lambda is its own unique unnamed type.
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a
public inline function call operator (13.5.4) whose parameters and
return type are described by the lambda-expression’s
parameter-declaration-clause and trailing-return-type respectively.
Since lambda has function call operator defined you can assign it to std::function
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no
lambda-capture has a public non-virtual non-explicit const conversion
function to pointer to function having the same parameter and return
types as the closure type’s function call operator. The value returned
by this conversion function shall be the address of a function that,
when invoked, has the same effect as invoking the closure type’s
function call operator.
If the lambda does not capture anything it can be converted to a function pointer.
Normally, a lambda expression is an anonymous function object and it doesn't have a named type. However, sometimes we can use type erasure. If a lambda expression doesn't capture any arguments like your example, it can convert to function pointer implicitly. If a lambda expression captures some arguments, it can convert to std::function.

Compiler variance: type of `this` when value-captured in mutable lambda defined in a const member function

The following program
#include <type_traits>
struct S {
void f() const {
(void)[*this]() mutable {
static_assert(
std::is_same_v<decltype(this), S *>); // Fails with GCC & MSVC
static_assert(
std::is_same_v<decltype(this), const S *>); // Fails with Clang
(void)this;
}
();
}
};
int main() {}
contains a mutable lambda which captures *this by value ([*this]), and which does so in a const-qualified member function. The program is rejected by GCC due to #1, and rejected by Clang due to #2 (and conversely accepted):
GCC(1) and MSVC thinks decltype(this) is const S *
Clang(1) thinks decltype(this) is S *
(1) Various compiler versions for C++17 and C++20
DEMO.
Which compiler is right here?
GCC/MSVC are correct, Clang is reasonable but incorrect
[expr.prim.lambda.closure[/12:
The lambda-expression's compound-statement yields the function-body ([dcl.fct.def]) of the function call operator, but for purposes of name lookup, determining the type and value of this and transforming id-expressions referring to non-static class members into class member access expressions using (*this) ([class.mfct.non-static]), the compound-statement is considered in the context of the lambda-expression.
means [class.this]/1 applies:
In the body of a non-static ([class.mfct]) member function, the keyword this is a prvalue whose value is a pointer to the object for which the function is called. The type of this in a member function whose type has a cv-qualifier-seq cv and whose class is X is “pointer to cv X”.
GCC/MSVC and Clang may be applying [class.this]/1, particularly regarding the cv-qualifier of the member function, to either of
the cv-qualification of the member function in which the lambda is defined, S::f() in OP's example, which is const-qualified, or
the cv-qualification of the function call operator of the lambda, which is not const-qualified (due to mutable),
particularly GCC and MSVC choosing interpretation 1, whereas Clang chooses interpretation 2. We may note that if we slightly tweak OP's example to capture the lambda by capturing *this by reference, [this], all compilers agree that decltype(this) in the lambda is const S * (which makes sense).
Based on the standard passages above, particularly [expr.prim.lambda.closure]/12, I would argue that Clang is wrong to let this be non-const-qualified when *this has been value-captured by a mutable lambda from within a const-qualified method. Even if it could make sense to base constness for a value-copied *this on the constness of the function call operator of the lambda's closure type, the standard does not support it.
We may finally note that we see the same behaviour if using overload resolution instead of decltype (i.e. comparing this in our outside of an unevaluated context), namely GCC and MSVC preserving constness of the copy-captured *this, where Clang does not.
Bug reports?
I have not been able to find any Clang bug reports for this, and have hence filed:
Bug 51524 - '*this' captured by copy does not preserve constness of '*this' in mutable lambda

Are captureless lambda guaranteed to be empty by the standard?

I'm searching for a way to identify empty (captureless) lambdas from other lambdas in a template function. I'm currently using C++17 but I'm curious for C++20 answers too.
My code looks like this:
template<typename T>
auto func(T lambda) {
// The aguments of the lambdas are unknown
if constexpr (/* is captureless */) {
// do stuff
}
}
Is it guaranteed by the C++ standard (17 or 20) that a captureless lambda, which is convertible to a function pointer, will also make std::is_empty yield true?
Take this code as an example:
auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures
static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?
Live example
No, in fact, the standard explicitly grants permission for lambdas to have a size that doesn't line up with their declaration. [expr.prim.lambda.closure]/2 states
The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [ Note: This determines the set of namespaces and classes associated with the closure type ([basic.lookup.argdep]). The parameter types of a lambda-declarator do not affect these associated namespaces and classes. — end note ] The closure type is not an aggregate type. An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:
the size and/or alignment of the closure type,
whether the closure type is trivially copyable ([class.prop]), or
(2.3)
whether the closure type is a standard-layout class ([class.prop]).
An implementation shall not add members of rvalue reference type to the closure type.
emphasis mine
So this allows the implementation to give the lambda a member even if it is capture-less. I don't think any implementation ever would, but they are legally allowed to do so.

Using of not captured variable in lambda

I can not quite understand an example from C++14 standard draft N4140 5.1.2.12 [expr.prim.lambda].
A lambda-expression with an associated capture-default that does not explicitly capture this or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an initcapture’s associated non-static data member), is said to implicitly capture the entity (i.e., this or a variable) if the compound-statement:
odr-uses the entity, or
names the entity in a potentially-evaluated expression where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
[ Example:
void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [=](auto a) {
int selector[sizeof(a) == 1 ? 1 : 2]{};
f(x, selector); // OK: is a dependent expression, so captures x
};
}
—end example ]
All such implicitly captured entities shall be declared within the reaching scope of the lambda expression.
[ Note: The implicit capture of an entity by a nested lambda-expression can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. —end note ]
I thought that the beginning of a phrase a lambda-expression with an associated capture-default should prohibit any implicit capture (and it's confirmed by comment), therefore #1 call will lead to an error (something about using not captured variable). So how it works? What will be first argument of f? What if g will be called after exiting test() scope? What if I change #1 signature to void(const int&)?
--
upd: Thanks to all for explanation of how it works. Later I'll try to find and post references to standard about this case.
As T.C. said in his comment, #1 does not require a capture as x is known at compile time and is therefore baked into the lambda. Not unlike how the function f is known at compile time so it doesn't need to be captured.
I believe if you change f's signature to int const & you are now attempting to pass the address of the constant which is on the stack, thus subject to changes, and it would require capturing x by value or reference.

What type do lambdas get compiled into? [duplicate]

This question already has answers here:
What is the type of lambda when deduced with "auto" in C++11?
(8 answers)
Closed 8 years ago.
As I know all data types must be known at compile time, and lambda is not a type. Does lambda got translated into anonymous struct with operator() or std::function wrapped?
For example,
std::for_each(v.begin(), v.end(), [](int n&){n++;});
A variation of the as-if rule, the C++11 standard says:
§5.1.2/3 [..] An implementation may define the closure type
differently from what is described below provided this does not alter
the observable behavior of the program other than by changing:
— the size and/or alignment of the closure type,
— whether the closure type is trivially copyable (Clause 9),
— whether the closure type is a standard-layout class (Clause 9), or
— whether the closure type is a POD class (Clause 9).
I believe this is what people mean when they say that it's unspecified. However what's guaranteed as already stated in the other answers is the following:
Original author: Lightness Races in Orbit
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed
non-union class type — called the closure type — whose properties
are described below. This class type is not an aggregate (8.5.1). The
closure type is declared in the smallest block scope, class scope, or
namespace scope that contains the corresponding lambda-expression.
[..]
The clause goes on to list varying properties of this type. Here are
some highlights:
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and
return type are described by the lambda-expression’s
parameter-declaration-clause and trailing-return-type respectively. [..]
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const
conversion function to pointer to function having the same parameter
and return types as the closure type’s function call operator. The
value returned by this conversion function shall be the address of a
function that, when invoked, has the same effect as invoking the
closure type’s function call operator.
From the standard §5.1.2.3:
The type of the lambda-expression... is a unique, unnamed non-union class type
It is its own type. Every time. So for instance:
auto a = []{ return 1; };
auto b = []{ return 1; };
a and b will necessarily have different types. They are both convertible to std::function<int()>, but not to each other:
std::function<int()> c = a; // OK
a = b; // NOPE
Adding a few more examples to add some clarity:
decltype(a) a2 = a; // OK, explicitly specifying the correct type
template <typename F>
void foo(F f) { ... }
foo(a); // calls foo<decltype(a)>, not foo<std::function<int()>
A lambda expression constructs an unnamed type, with each one having a different type. They are not std::function implementations. More info is provided here:
What is a lambda expression in C++11? and here: How to convert a lambda to an std::function using templates
You can unveil the type on your specific compiler with a trick like this:
void foo(int);
int main() {
auto a = []{ return 1; };
auto b = []{ return 1; };
foo(a);
foo(b);
return 0;
}
Compiling with clang on my mac gives:
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo'
foo(a);
^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument
void foo(int);
^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo'
foo(b);
^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument
void foo(int);
#Barry points out that you can use typeid instead. If I print out typeid(a).name() and typeid(b).name() on my system, I get:
Z4mainE3$_0
Z4mainE3$_1
which demangle to
main::$_0
main::$_1
Just wanted to include this for completeness. I actually find the error message version a little more informative. :)