1

with C++20, we get templated lambdas to do things like that:

    auto t = []<typename T>(T tmp){std::cout << tmp << std::endl;};

But what if I need to specify the exact type via std::function<>? (don't rely on auto).

Is it possible to store the templated lambda into a std::function<> wrapper? e.g. similar to the following?

    template<typename T>
    std::function<void(T)>  t = []<typename T>(T tmp){std::cout << tmp << std::endl;};

and use it like a regular template-function?

byteunit
  • 991
  • 4
  • 15
  • 1
    What is the actual problem you're trying to solve? Note that generic lambdas aren't new in C++20, we've had them since C++14, it's just the specific spelling is new. – Barry Oct 03 '19 at 19:32
  • 1
    isn't `auto` a "templated" lambda? like `auto t = [](auto tmp){std::cout << tmp << std::endl;};` – fas Oct 03 '19 at 19:33
  • I want to add the lambda into a class as a non-static member. And therefore, it must not be defined with auto. – byteunit Oct 03 '19 at 19:38
  • Can't catch the point! "But what if I need to specify the exact type?" The exact type of the parameter(s) for the lambda/function call? If so, why we need a template/auto inside the lambda definition? – Klaus Oct 03 '19 at 19:41
  • I don't want to say `auto t = templated lambda`. Instead I want to say `std::function<...> = templated lambda`. – byteunit Oct 03 '19 at 19:43
  • @byteunit Ok, so phrase your question in the form of "How do I add a lambdas as a non-static member?" That seems to have nothing to do with either the familiar template syntax for lambdas or `std::function`. – Barry Oct 03 '19 at 19:44
  • @Barry But I also need it also in other contextes, the question title is therefore correct. – byteunit Oct 03 '19 at 19:47
  • @byteunit Well, what are those other contexts? This is why I'm asking what're you actually trying to do. See [XY problem](https://meta.stackexchange.com/q/66377/297908). – Barry Oct 03 '19 at 19:52
  • @byteunit `std::function != lambda` because the first one for example is copy-constructible, but lambdas may be not, when you capture something not copy-constructible – fas Oct 03 '19 at 19:56
  • @barry I also want to specify functions with the exact return type. And the exact return type may be the lambda. – byteunit Oct 03 '19 at 19:56
  • @byteunit I don't understand what that means. Exact return type of what? "Exact return type may be the lambda" doesn't make sense - you're returning a lambda? – Barry Oct 03 '19 at 20:03
  • @barry, i sorry, with exact i mean a callable thing with the signature of `template std::function` or something similar. – byteunit Oct 03 '19 at 20:06
  • Lambdas have unnamed types, you *have* to use `auto` (or `decltype`). `std::function` is merely a clevery written class that can store functions/lambas, it's NOT the actual type of a lambda. – HolyBlackCat Oct 03 '19 at 20:06

1 Answers1

4

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");
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Yeah thanks for the answer, that or something similar will be what I will do. I only wanted to make sure if there is something I have not considered. – byteunit Oct 03 '19 at 20:12