Functors

https://www.youtube.com/watch?v=shqvSkk8r0M&t=183s

Hi guys I am following the tutorial on functors above @2:55 he says you can call a functor a bit differently with something called a parameterized function(name doesn't sound like it's correct any function with arguments is a paramaeterized function lol)

anyway I tried doing this myself and get an error,I have never seen this done before so I don't know how it works for him,

I am using c++11.

***EDIT*********

I noticed a problem in my code I should have removed the f and just left it as Functor(4)("hi");
but to be honest this confuses me even more,how the above line is not creating an instance of a Functor so how can we use it in this way?


thanks



thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  class Functor{

   public:
       Functor(int x){

       }
       void operator()(string x){

          cout << x << endl;
       }
};

int main()
{
    Functor f(4)("hey");
}
Last edited on
Hi adam, the difference is, in the video, that guy's main function declares a temporary X object. It doesn't have a name.
X(8)("Hi"); first constructs a temporary object with X(8), and then calls its () operator.

But you're making a named, non-temporary object, named f, so you can't apply the same syntax.
If you don't want to make a temporary variable, you have to split it into two calls.

Options A:
1
2
Functor f(4);
f("hey");


Option B:
 
Functor(4)("hey");


______________________________

Edit in response to edit:
,how the above line is not creating an instance of a Functor so how can we use it in this way?
Functor(4); does create an instance of a Functor. But it's a temporary (unnamed) instance of it.

It's just like if you were to do something like this:
1
2
3
4
5
6
class Foo { };

int main()
{
    Foo foo = Foo(); // the "Foo()" is a temporary object.
}
Last edited on
Thanks Ganado that makes sense :)
To use the constructor argument later, save it in a member variable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

class Functor {
    int x;
public:
    Functor(int x) : x(x) {}
    void operator()(string s) { cout<< s <<','<< x <<'\n'; }
};

int main() {
    Functor(4)("hey");
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


class Functor{

   public:
       Functor(int x){

       }
       void operator()(string x){

          cout << x << endl;
       }
       void sayHello(){

         cout << "hello" << endl;
       }
};

int main(){

    Functor(4)("hey");
    Fucntor(8).sayHello();



if Fucntor(4)("hey"); is legal how come Functor(8).sayHello(); isn't?

thanks
I don't know what you are doing wrong.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

class Functor {
    int x;
public:
    Functor(int x) : x(x) {}
    void operator()(string s) { cout<< s <<','<< x <<'\n'; }
    void sayHello() { cout<< "yo: " << x << '\n'; }
};

int main() {
    Functor(4)("hey");
    Functor(8).sayHello();
    return 0;
}

One of the more enjoyable use-cases of functors is custom sorting. For example:
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
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

using namespace std;

struct Stuff
{
    Stuff(double score) : score(score)
    {
    }
    double score;
};

class StuffSortDescending
{
public:    
    bool operator()(const Stuff& a, const Stuff& b)
    {
        return a.score > b.score;
    }
};

void Show(const vector<Stuff>& v)
{
    for (auto& s : v)
        cout << s.score << endl;
}

int main() 
{
    double lower_bound = 0;
    double upper_bound = 10000;
    std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
    std::random_device rd;
    std::default_random_engine eng(rd());
    
    vector<Stuff> stuff;
    for (int x=1; x<=10; ++x)
    {
       stuff.emplace_back(unif(eng));
    }
    
    cout << "Stuff before sorting:" << endl;
    Show(stuff);

    cout << "\nStuff after descending sort:" << endl;
    sort(stuff.begin(), stuff.end(), StuffSortDescending());
    Show(stuff);

    return 0;
}


Possible output:
Stuff before sorting:
3324.77
4095.17
1160.53
5511.24
1035.97
1495.7
4068.46
5283.35
6667.23
268.406

Stuff after descending sort:
6667.23
5511.24
5283.35
4095.17
4068.46
3324.77
1495.7
1160.53
1035.97
268.406
I am just discovering use cases of functors today and I must say they are pretty neat,from what I read they are more expensive than function pointers but a lot more powerful well from what I can see

1
2
3
4
5
6
7
8
9
10
11
12
13
14

double lower_bound = 0;
    double upper_bound = 10000;
    std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
    std::random_device rd;
    std::default_random_engine eng(rd());
    
    vector<Stuff> stuff;
    for (int x=1; x<=10; ++x)
    {
       stuff.emplace_back(unif(eng));
    }



why didn't you just use the push_back() function?
Last edited on
i'm hinting at the compiler to create my Stuff object and then std::move it into the vector in-place. In the case of push_back, it'll create a Stuff object and then it might make a copy during the append.

*shrug*, compilers are smart these days, so both could turn out the same
Topic archived. No new replies allowed.