I am experimenting with lambdas and the fact that different lambda expressions have different types, even though they are the same. Consider this code
#include <iostream>
template <typename T> void once(T t){
static bool first_call = true;
if (first_call) t();
first_call = false;
}
int main() {
int counter = 0;
auto a = [&counter](){counter++;};
once(a);
once(a);
std::cout << counter; // 1
auto b = a; // same type
once(b);
std::cout << counter; // 1
auto c = [&counter](){counter++;}; // different type
once(c);
once(c);
std::cout << counter; // 2
}
This prints 112
, ie a
and b
are of course of same type and c
has a different type.
Is the compiler allowed to let c
be of the same type than a
?
I mean the expressions are identical and it would be an obvious optimization.
PS: In case the capture prevents such an optimization, then what about lambdas without capture?
related: what is the type signature of a c++11/1y lambda function? and Can the 'type' of a lambda expression be expressed?
Lambda functions can have only one expression.
Since a lambda function can only provide the implementation for 1 method it is mandatory for the functional interface to have ONLY one abstract method.
The lambda expressions have a very simple, precise syntax and provide flexibility to specify the datatypes for the function parameters. Its return type is a parameter -> expression body to understand the syntax, we can divide it into three parts.
Types of Lambda Body In Java, the lambda body is of two types. () -> System. out. println("Lambdas are great");
Is the compiler allowed to let
c
be of the same type thana
?
No. [&counter](){counter++;}
is a lambda expression and per [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, whose properties are described below.
So, for each lambda expression, even if it is identical to a previous one, you will get a unique type.
You can use typeid
to check that this is the case like:
#include <iostream>
#include <typeinfo>
template <typename T> void once(T t){
static bool first_call = true;
std::cout << typeid(t).name() << std::endl;
if (first_call) {
t();
}
first_call = false;
}
int main() {
int counter = 0;
auto a = [&counter](){counter++;};
once(a);
once(a);
std::cout << counter << std::endl; // 1
auto b = a; // same type
once(b);
std::cout << counter << std::endl; // 1
auto c = [&counter](){counter++;}; // different type
once(c);
once(c);
std::cout << counter << std::endl; // 2
}
result:
Z4mainEUlvE_
Z4mainEUlvE_
1
Z4mainEUlvE_
1
Z4mainEUlvE0_
Z4mainEUlvE0_
2
and you can see there are two function template instantiations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With