There is a problem with the templated std::function
. It's not one std::function
, but many. The compiler will create more and more global data as you use more types.
Also, template argument deduction will not work, since the std::function
variable is templated, not the operator()
of the std::function
.
Also, you don't need C++20 to have this problem, try this with C++14:
// equivalent to the templated lambda, just different syntax
auto t = [](auto tmp){std::cout << tmp << std::endl;};
But what if I need to specify the exact type via std::function<>? (don't rely on auto).
The thing is each lambdas has a unnamed unique type that cannot be written. auto
is the only way to create a variable of a lambda type.
Use std::function
only when you need type erasure, when you need a variable of an unknown type but known interface (like a operator()
). A std::function
is not free and has runtime and binary size cost. It's a type erasure wrapper for callable type.
Now what if you really need the std::function
?
Well, std::function
can only deal with known type. For example, this will work:
std::function<void(int)> t = []<typename T>(T arg) { /* ... */ };
But will only calle the int
version of the lambda.
Asking std::function
to have a templated operator()
is like asking for a virtual templated function. It cannot be implemented.
What if you want to use a type with a known name?
Then don't use lambdas! They may not be the tool you need!
Here's an equivalent not using auto nor std::function
:
struct MyLambda {
template<typename T>
auto operator()(T arg) { /* ... */ }
};
MyLambda my_function_returning_lambda() {
// ...
}
// ...
MyLambda lambda = my_function_returning_lambda();
lambda(1);
lambda("works");