passing/returning functionals by value ?

I am trying to understand the extent to which lambda, std::binding and std::function can be passed by value and used outside the context in which they were created.

1. Is it correct that value “captured” by a lambda or a biding are stored by value?

2. Is it correct that a lambda or std::binding can be returned or passed by value or copied, and so they will execute properly outside the context in which they will have been created (assuming the captured values don’t reference objects that are not valid).

3.Is this also true of a std::function<> ? If a std::function<> wraps a binding or a lambda, does it somehow store the binding or the lambda, including all their captured data)

4.Then how is the content of a std::function stored ? A std::function<> type must have a fixed length but the objects it wraps such as a std::binding <> can be of very different lengths ? Perhaps std::function is a kind of a smart pointer pointing to a copy of the underlying functional ?

5.I guess that the “code” part of the function is not an issue. The programmatic content of a lambda or binding is compiled as part of the program and can always be referenced thru a pointer stored in the lambda, std::binding<> or std:: function<> object.

The attached code is inspired by https://en.cppreference.com/w/cpp/utility/functional/function

It illustrates that std::function<> can be returned by value and somehow seem to store objects that are larger (an std::function is like the Tardis, it is larger inside),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <functional>
#include <iostream>

struct Foo
{
  Foo (int num):num_ (num){}
  void print_add (int i) const{
    std::cout << num_ + i << '\n';
  }
  int num_;
};

void print_num (int i){
  std::cout << i << '\n';
}

struct PrintNum{
  void operator() (int i) const{
    std::cout << i << std::endl;
  }
};

std::function < void (int) > display (int i, int v)
{
  Foo foo (v);
  switch (i){
    case 0:
      return print_num;
    case 1:{
      auto ret = std::bind (&Foo::print_add, foo, std::placeholders::_1);
      std::cout << "sizeof(std::bind ...) =" << sizeof (decltype (ret)) << std::endl;
      return ret;}
    case 2:{
        auto ret = [v] (int x){std::cout << x + v << std::endl;};
        std::cout << "sizeof([v] (int x) ...) =" << sizeof (decltype (ret)) << std::endl;
        return ret;
    }
    case 3:{
        double t[10];
        for (int i = 0; i < 10; ++i){
	    t[i] = double (v) * i;}
	    auto ret = [t] (int x){
	        for (int i = 0; i < 10; ++i){
	            std::cout << t[i] + x << ", ";
	        };
	        std::cout << std::endl;
            };
        std::cout << "sizeof([v] [t] (int x) ...) =" << sizeof (decltype (ret)) << std::endl;
        return ret;
        }
    default:
        return [](int){std::cout << "default" << std::endl;};
    }
}


int main ()
{
  std::function < void (int) > fun[4];
  for (auto i = 0; i < 4; ++i){
      fun[i] = display (i, i * 11);
    }

  std::cout << "sizeof(std::function <void (int)> =" << sizeof (std::function <void (int) >) << std::endl << std::endl;;

  for (auto i = 0; i < 4; ++i){
      fun[i] (12);
    }
    
}


Last edited on
1. Is it correct that value “captured” by a lambda or a biding are stored by value?

With lambda expressions you can choose if you want to capture by reference or by value.

2. Is it correct that a lambda or std::binding can be returned or passed by value or copied, and so they will execute properly outside the context in which they will have been created (assuming the captured values don’t reference objects that are not valid).

Yes.

3.Is this also true of a std::function<> ? If a std::function<> wraps a binding or a lambda, does it somehow store the binding or the lambda, including all their captured data)

Yes.

4.Then how is the content of a std::function stored ? A std::function<> type must have a fixed length but the objects it wraps such as a std::binding <> can be of very different lengths ? Perhaps std::function is a kind of a smart pointer pointing to a copy of the underlying functional ?

Some implementations has a "small buffer optimization" which means that it will store the callable inside the std::function object if it's small enough. Otherwise, it'll have to store it on the heap.

5.I guess that the “code” part of the function is not an issue. The programmatic content of a lambda or binding is compiled as part of the program and can always be referenced thru a pointer stored in the lambda, std::binding<> or std:: function<> object.

Yeah, it's just a function pointer.
Excelllent! Thanks for taking the time to respond.
These are very neat objects!
Last edited on
Topic archived. No new replies allowed.