I'm aware that there's no default constructor for lambda closure type. But does that mean it's impossible to instantiate it after it being passed as a template parameter?
Consider the following minimal example:
#include <iostream>
template <typename FuncType>
std::pair<int,int> DoSomething() {
return FuncType()(std::make_pair(1,1));
}
int main() {
auto myLambda = [](std::pair<int,int> x) {
return std::make_pair(x.first*2,x.second*2);
};
std::pair<int,int> res = DoSomething<decltype(myLambda)>();
return 0;
}
For performance reasons, I can't use std::function
to avoid virtual pointer calls. Is there a way to do this? I need to instantiate that lambda once and use it many times inside that function.
How does the standard library make it work when decltype(myLambda)
is passed to something like std::map
comparators in the template parameter?
Closures and the Lambdas 1 , the capability that allows a method or a function to reference a non-local variable or value is called closure. 2 Non-local Variables. In C#, accessing a variable outside the scope of a function is possible and considered normal. ... 3 Lambda Functions. ... 4 Closures. ... 5 Conclusion. ...
Lambdas, also known as closures, are unnamed function objects in C++. Unnamed means we cannot know or name their type . Because their type is unknown to us lambdas can only ever be stored in an auto variable on the stack.
Unnamed means we cannot know or name their type . Because their type is unknown to us lambdas can only ever be stored in an auto variable on the stack. Function means lambdas implement the function call operator ( ()) and object means lambdas can store data, just like a struct or class.
Under the final C++11 spec, if you have a lambda with an empty capture specification, then it can be treated like a regular function and assigned to a function pointer. Here's an example of using a function pointer with a capture-less lambda: typedef int (*func) (); func f = [] () -> int { return 2; }; f ();
Although this feature is coming in C++20 (see songyuanyao's answer), you don't actually need that in this case. You can just pass the lambda as a function parameter of type FuncType
and call that multiple times:
template <typename FuncType>
std::pair<int,int> DoSomething(FuncType f)
{
return f(std::make_pair(1,1));
}
int main()
{
auto myLambda = [](std::pair<int,int> x) {
return std::make_pair(x.first*2,x.second*2);
};
std::pair<int,int> res = DoSomething(myLambda);
}
I'm aware that there's no default constructor for lambda closure type.
Yes, this is true until C++20. (Note that since C++20 if no captures are specified, the closure type has a defaulted default constructor.)
Closure types are not DefaultConstructible. Closure types have
a deleted (until C++14)
no (since C++14)
default constructor. (until C++20)
And
How does the standard library make it work when
decltype(myLambda)
is passed to something likestd::map
comparators in the template parameter?
There's nothing special for the standard library. If you specify a non-DefaultConstructible lambda as the comparator type for std::map
, you have to pass an object to the constructor, std::map
will initialized its comparator via copy; lambda has copy and move constructor.
You can change your code to the same way as std::map
's constructor:
template <typename FuncType>
std::pair<int,int> DoSomething(const FuncType& f = FuncType()) {
// auto z(f); // you can take a copy if necessary
return f(std::make_pair(1,1));
}
then
auto myLambda = [](std::pair<int,int> x) {
return std::make_pair(x.first*2,x.second*2);
};
std::pair<int,int> res = DoSomething<decltype(myLambda)>(myLambda);
LIVE
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