0

What is the advantage of storing a lambda in a std::function as opposed to an auto variable. For example in the code below I store the lambda in variable f1 rather than in std::function f.

#include <iostream>
#include <functional>
using namespace std;

void global_f() {
    cout << "global_f()" << endl;
}

struct Functor {
    void operator()() { cout << "Functor" << endl; }
};

int main() {
    std::function<void()> f;

    cout << "sizeof(f) == " << sizeof(f) << endl;

    f = global_f;
    f();

    auto f1 = [](){ cout << "Lambda" << endl;};
    f1();

    Functor functor;
    f = functor;
    f();
}
Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
cherry aldi
  • 327
  • 1
  • 10
  • You may or may not have a performance increase, depending on the lambda, as `std::function` is type erased. – DeiDei Nov 07 '18 at 14:50
  • there is no advantage, but sometimes you dont know whether you get a lambda or some other callable and `std::function` can wrap more than just lambdas – 463035818_is_not_an_ai Nov 07 '18 at 14:55
  • If you want to store a function object something and you want it to have a certain signature is one of the few use cases left for `std::function`. – NathanOliver Nov 07 '18 at 14:58
  • If you need the things that `std::function` does, use `std::function`. I you don't need them, don't use it. – Pete Becker Nov 07 '18 at 15:00
  • @user463035818, how is the linked question a duplicate of this one? The question there is "which is more expensive, auto or std::function?" The question here is "why would I use std::function instead of auto?" – Peter Ruderman Nov 07 '18 at 15:00
  • You can *change* the value of `f`, you *can't* change the value of `f1` – Caleth Nov 07 '18 at 15:00
  • @PeterRuderman the question is not exactly the same, but the answers still explains the difference between using a lamda and using a lambda wrapped in a `std::function` – 463035818_is_not_an_ai Nov 07 '18 at 15:01
  • @user463035818, the answers discuss why `std::function` is generally more expensive. They do not discuss the scenarios in which you'd use it over `auto`. – Peter Ruderman Nov 07 '18 at 15:03
  • @PeterRuderman from the top answer: "std::function can store an arbitrary callable". The scenario is when you need to deal with arbitrary callables – 463035818_is_not_an_ai Nov 07 '18 at 15:04
  • @user463035818, that could do with some elaboration, don't you think? – Peter Ruderman Nov 07 '18 at 15:05
  • @PeterRuderman agreed :) – 463035818_is_not_an_ai Nov 07 '18 at 15:06
  • not a duplicate, but highly related: https://stackoverflow.com/questions/48007520/is-stdfunction-heavier-than-auto-storing-lambda-function?noredirect=1&lq=1 – 463035818_is_not_an_ai Nov 07 '18 at 15:08
  • @Caleth thats an interesting way to put it. I mean I know that there is only one value of each lambda type, but I never realized that this implies a lambda cannot be "modified" – 463035818_is_not_an_ai Nov 07 '18 at 15:11
  • 1
    @user463035818 the closure type explicitly deletes assignment. There can be multiple values of a lambda type, eg if you return it from an auto function, and they can capture different values – Caleth Nov 07 '18 at 15:20
  • 1
    @user463035818 E.g. `auto make = [](int val){ return [val](){ std::cout << val; } }; auto one = make(1);` Adding `one = make(1);` would fail to compile – Caleth Nov 07 '18 at 15:24
  • @Caleth hm right. I am not yet too familiar with what lamdas cannot do. Sometimes I have the feeling that there are arbitrary restrictions, but then maybe I am trying to use a lambda for something they were not made for – 463035818_is_not_an_ai Nov 07 '18 at 15:25

1 Answers1

1

In your simple example, there is no advantage to storing the lambda inside a std::function. Often, storing a lambda using auto is more efficient, but it also highly restrictive. The auto version can serve only as a local variable. If you want to store the lambda for later use, then you must use a std::function.

For example, you might want to store the lambda inside a class member. Consider the following class:

class Foo
{
  std::function<void()> callback_;
public:
  void Bar(int value)
  {
    callback_ = [value] { DoStuff(value); }
  }
  /* other constructors and methods omitted */
}

In this case, you can't use auto because the lambda's type is anonymous and only available within the Bar method.

std::function is also useful when you want to use lambdas as arguments to regular functions. The function has no way to know the lambda's type, but it can declare a std::function parameter instead. For example:

void Foo(std::function<void()> callback);

...

Foo([](){ cout << "Lambda" << endl;});

It's worth pointing out that this does not apply to function templates. When using a lambda in such a context, it's usually a better idea to let the compiler deduce the lambda's type (similar to using auto). For example:

template <class F> void Foo(F&& callback) { /* details */ }

...

Foo([](){ cout << "Lambda" << endl;}
Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
  • sorry, i dont agree with your points. You **can** pass a lambda to a function `template void Foo(F f)` is preferable to using `std::function` if possible. Also I dont really understand what you mean with "If you want to store the lambda for later use, then you must use a std::function" – 463035818_is_not_an_ai Nov 07 '18 at 15:23
  • I'll elaborate on your second point. As I mentioned, you need `std::function` when passing the lambda to a _function_, not a function template. – Peter Ruderman Nov 07 '18 at 15:31
  • when i call my `foo` as `foo ( [](){} )` then that `foo` is a function not a function template. Afaik you cannot call a function template – 463035818_is_not_an_ai Nov 07 '18 at 15:33
  • @user463035818: "*if possible*" And what happens when it is *not* possible? There are many reasons why a particular function may not be able to be a template. Not only that, the template version can't take member pointers. – Nicol Bolas Nov 07 '18 at 15:46
  • @NicolBolas the answer contains much more details since I made my comment. Before the argument was roughly: "You need `std::function` when you want to pass a lambda to a function", which didnt really convince me. (now it got my upvote btw) – 463035818_is_not_an_ai Nov 07 '18 at 15:50