Fun With C++ Callbacks

I did some experiments with callbacks based on a snippet from ideone.com.

EventManagerBuild&Run
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <functional>

class EventManager
{
public:
    template<class F>
    void AddClient(F client)
    {
        clients.emplace_back(new EventClient<F>(std::move(client)));
    }
    
    void Emit()
    {
        std::for_each(clients.begin(), clients.end(), [](auto& client){ client->Respond(); });
    }
    
private:
    struct IEventClient
    {
        virtual ~IEventClient() { }
        virtual void Respond() = 0;
    };
    
    template<class F>
    struct EventClient : IEventClient
    {
        F f;
        EventClient(F&& f) : f(std::move(f)) { }
        void Respond() override { f(); }
    };
    
    std::vector<std::unique_ptr<IEventClient>> clients;
};

struct Foo { void operator()() const { std::cout << "Foo\n"; } };

struct Bar { int operator()() { std::cout << "Bar\n"; return 0; } };

struct Baz
{
    Baz() { id = ID++; obj_valid = true; std::cout << "ctor(id=" << id << ")\n"; };
    ~Baz() { std::cout << "dtor(id=" << id << ")\n"; obj_valid = false; };
    
    //Baz(const Baz& b) { id = b.id; obj_valid = b.obj_valid; std::cout << "cctor(id=" << id << ")\n"; };
    Baz(Baz&& b) { id = std::move(b.id); obj_valid = std::move(b.obj_valid); b.id = -1; b.obj_valid = false; std::cout << "mctor(id=" << id << ")\n"; };
    
    Baz(const Baz& b) = delete;
    Baz& operator=(const Baz&) = delete;
    
    void f(const std::string& s) const { std::cout << "Baz::f(\"" << s << "\", id=" << id << ", obj_valid=" << obj_valid << ")\n"; }    
    
    static int ID;
    int id{-1};
    bool obj_valid{false};
};

int Baz::ID;


int main()
{
    EventManager eventMan;

    eventMan.AddClient([]{ std::cout << "lambda\n"; });
    eventMan.AddClient(std::bind([](int i){ std::cout << "lambda+bind\n"; }, 1234));
    
    std::function<void()> f1 = []{ std::cout << "std::function\n"; };
    eventMan.AddClient(f1);
    
    std::function<double(double)> f2 = [](double d){ std::cout << "std::function+bind\n"; return d;};
    eventMan.AddClient(std::bind(f2, .5));
    
    eventMan.AddClient(Foo());
    eventMan.AddClient(Bar());

    eventMan.AddClient(std::bind(&Baz::f, Baz(), "baz_t")); // ctor and move
    eventMan.AddClient(std::bind(&Baz::f, std::make_shared<Baz>(), "baz_p")); // same with shared_ptr

    {
        //Baz baz; // ctor
        //eventMan.AddClient(std::bind(&Baz::f, baz, "baz_o")); // copy ctor and move
    }
    
    {
        Baz baz;
        eventMan.AddClient(std::bind(&Baz::f, std::move(baz), "baz_m")); // invokes copy ctor
    }
    
    {
        Baz baz;
        eventMan.AddClient(std::bind(&Baz::f, std::ref(baz), "baz_r")); // no copy, goes out of scope, UB
    }
    
    eventMan.Emit();
}

Simple Hexo Recipes

Create new post

1
$> hexo new post <title>

Test content locally

Generate content into the public directory and start a local server.

1
$> hexo generate && hexo server

The server detects most modifications made to posts/themes and regenerates on the fly -> no restart necessary, just reload the page.

Deploying

There is no local master branch. All work is done inside the local source branch.
Test changes locally, commit and push them to upstream. Then deploy the generated content:

1
$> hexo generate && hexo deploy

This will push the generated content to the upstream master branch. The deployment process will push to the repository specified inside _config.yml. The repository URL may be SSH.