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)
Related
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.
This question already has answers here:
C++11 lambda implementation and memory model
(2 answers)
Closed 7 years ago.
Where do lambdas and std::functions store variables captured by value?
int i = 1;
auto l = [i](void) mutable { return i++; };
std::function<int(void)> f = l;
Do they call the new operator? If I provide my own new operator, will it be used by lambdas?
From [expr.prim.lambda] 5.1.2(15)
An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture that is not of the form & identifier or & identifier initializer. For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is the type of the corresponding captured entity if the entity is not a reference to an object, or the referenced type otherwise. [ Note: If the
captured entity is a reference to a function, the corresponding data member is also a reference to a function. —end note ] A member of an anonymous union shall not be captured by copy.
emphasis mine
So a variable captured by value will be stored as member of the closure type. The closure type is unspecified as per 5.1.2(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. This class type is neither an aggregate (8.5.1) nor a literal type (3.9). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression.
At compile time lambdas are actually turned into classes. So if you had the following.
int a; Widget widget;
auto somelambda = [=a,&widget](){
}
You could actually think of it as
class SomeLambda
{
int a;
Widge& w;
...
}
Which should make you really cautious because you can have dangling references.
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. :)
I was trying to validate this statement (my emphasis) in paragraph §5.1.1/8 (page 87) of the C++11 Standard
A nested-name-specifier that denotes a class, optionally followed by
the keyword template (14.2), and then followed by the name of a member
of either that class (9.2) or one of its base classes (Clause 10), is
a qualified-id; 3.4.3.1 describes name lookup for class members that
appear in qualified-ids. The result is the member. The type of the
result is the type of the member. The result is an lvalue if the
member is a static member function or a data member and a prvalue
otherwise.
with the following snippet:
#include <iostream>
namespace N {
class A {
public:
int i;
void f();
};
}
int main()
{
std::cout << &N::A::f << '\n';
std::cout << &N::A::i << '\n';
}
clang and gcc compile this code and VS2013 requires the definition of the member function f.
All three of them print
1
1
but I have no idea where these numbers come from.
live example
According to the paragraph highlighted above the expressions N::A::f is a prvalue, as f is not a static member function. Nonetheless, I was able to take its address in the code.
At the same time, in §5.3.1/3 one reads (emphasis mine):
The result of the unary & operator is a pointer to its operand. The
operand shall be an lvalue or a qualified-id. If the operand is a
qualified-id naming a non-static member m of some class C with type T,
the result has type “pointer to member of class C of type T” and is a
prvalue designating C::m.
which gives the impression that neither N::A::f nor N::A::i are lvalues, as they are qualified-ids.
but I have no idea where these numbers come from.
Pointer-to-members aren't pointers. No operator<< can output their original value, the best and only match is the one that outputs bool values. Thus they are converted to bool (which obviously yields true) and the output is 1. Try to insert std::boolalpha and check the output again.
Nonetheless, I was able to take its address in the code.
How is that a surprise to you? You quoted the part that allows and explains this exact construct. It clearly states that taking the adress of a qualified-id that names a non-static member designates that member.
qualified-ids are not only lvalues or rvalues. It completely depends on context. If they designate non-static members from outside that members class or any subclass of it, they have to be prvalues as they don't designate any specific object but rather a value (or information, in other words -- the type and an offset).
I can't find anything about throwing exceptions during constructing closure object.
It's oblivious that this expression can throw during copy construction of the vector:
auto v = std::vector<int>(1000000);
[v]{};
But what about empty or "by reference" capture lists like this:
[&]{};
I'm speaking only about construction of closure object now. Calling isn't interesting.
I read 5.1.2 Lambda expressions [expr.prim.lambda], but found nothing special about nothrow guarantee.
According to the standard (draft n3337), §5.1.2/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. 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 a nutshell, a lambda expression ultimately instantiates an anonymous type (known only to the compiler), containing member variables that store the values indicated in the capture list. So imagine you saw a class that looked like this:
class __IgnoreMe__
{
std::vector<int>& _v;
public:
__IgnoreMe__(std::vector<int>& v)
: _v(v)
{
}
void operator()()
{
}
};
(Note: this isn't exactly how the class created by the compiler looks. The standard lays out specific requirements for generated classes, which I've left out for brevity's sake.)
Now imagine you instantiate that class like this:
auto v = std::vector<int>(1000000);
auto my_lambda = __IgnoreMe__(v);
Can the instantiation of my_lambda throw an exception? If so, then the construction of the closure object can throw an exception. (It can't, in this case.)
As for providing nothrow guarantees, the standard doesn't require compilers to account for this, but it doesn't prevent them from doing it either. The end of §5.1.2/3 states:
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).