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.
Related
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
}
Every lambda should have a unique unknown type.. is it guaranteed that two lambdas into the same scope have different types?
int main() {
auto l1 = [](){};
auto l2 = [](){};
static_assert(std::is_same<decltype(l1), decltype(l2)>::value == false, "Types cannot be equal!");
}
This works but I'd like to know if it's guaranteed that the assert will never fire.
Yes, each lambda expression produces a unique type ([expr.prim.lambda]/3):
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below.
[emphasis added]
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. :)
This question already has answers here:
What is the type of lambda when deduced with "auto" in C++11?
(8 answers)
Closed 6 years ago.
There is this code:
auto fun = [](int x)->int {return x + 1; };
std::cout << typeid(fun).name() << std::endl;
The result is: Z4mainEUliE_ but c++filt doesn't seem to explain what is it. What is type of lambda expression?
§5.1.2/3 states:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type
It goes on to say more, but that's the most important bit. A lambda is basically an instance of an anonymous class.
Incidentally, the demangled form of your lambda is main::$_0.
The type of a lambda function is unspecified by the standard (§5.1.2):
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union classtype — 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.
It then goes on listing the exact properties a closure type should have.
Therefore there is no general type for a lambda function to have. The compiler will generate a new functor type with unspecified name for each lambda function
What is type of lambda expression?
The type of a lambda expression (the so-called closure) is an unnamed class type with a function call operator automatically generated by the compiler. The internal name the compiler will give it is unspecified.
According to Paragraph 5.1.2/3 of the C++11 Standard:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion
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. [...]
Also notice, that the name() member function of the type_info class (the type returned by typeid()) is also implementation-dependent, and the Standard does not require it to be meaningful for a human.
Per Paragraph 18.7.1:
const char* name() const noexcept;
9 Returns: An implementation-defined NTBS.
10 Remarks: The message may be a null-terminated multibyte string (17.5.2.1.4.2), suitable for conversion and display as a wstring (21.3, 22.4.1.4)
I have a class db_interface. And defined a lambda type:
typedef void (*db_interface_lambda)();
When I create lambda in class in such way: [](){ /* do something */ }, it has good type (db_interface_lambda), but when I use [this](){ /* do something */ }, the compiler starts to shout at me.
cannot convert ‘db_interface::db_interface(std::ifstream&)::<lambda()>’ to ‘std::map<std::basic_string<char>, void (*)()>::mapped_type {aka void (*)()}’ in assignment
How to solve that problem? What is the correct type?
Because lambdas are only implicitly convertible to function pointers if and only if they do not capture anything.
§5.1.2 [expr.prim.lambda] p6
The closure type for a lambda-expression with no lambda-capture ([] is empty) 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.
Btw, what you typedef'd there is a function pointer, not a lambda type. Lambda expressions have a unique, unnamed, nonunion class type. You can not name them.
§5.1.2 [expr.prim.lambda] p3
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type
You're trying to call something that wants a function pointer. A captureless lambda can be converted to a function pointer automatically, but once you write [this] it ceases to be captureless - you're capturing this, so it's an error.
The solution is to change the type to be a std::function, not a pointer to a function. std::function erases the type of the "functor" it "wraps" so you can still pass a function pointer as well as a lamba with a capture.
Lambdas that do not capture anything are essentially free functions, and thus they are convertible to ordinary function pointers.
Lambdas that do capture are essentially full classes, and they cannot simply be converted to a free-function pointer. (A capturing lambda is really essentially the same predicate functor class that you would have written in C++ before we had lambdas.)
Either version of lambda is convertible to std::function<void()>, which is what the mapped type of your map should be.