C++不定长参数委托

思路

用变长参数模板定义类,用单链表保存函数对象。使用了std::bindstd::integer_sequence自动生成占位符来简化成员函数的绑定

实现

Event.h

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
#pragma once

#include <functional>
#include <forward_list>

template <int N>
struct Placeholder {
static_assert(N > 0, "invalid placeholder index");
};

namespace std {
template <int N>
struct is_placeholder<Placeholder<N>> : integral_constant<int, N> {};
}

template<typename... Args>
class Event {
public:
using Function = std::function<void(Args...)>;
using Container = std::forward_list<Function>;
using Iterator = typename Container::const_iterator;

Iterator Add(Function func) {
_funcs.emplace_front(func);
return _funcs.cbegin();
}

template<typename T>
Iterator Add(void(T::* func)(Args...), T& obj) {
return _add(func, obj, std::make_integer_sequence<int, sizeof...(Args)>{});
}

void Remove(Iterator iterator) {
if (iterator == _funcs.cbegin()) {
_funcs.pop_front();
return;
}
auto lastIt = _funcs.cbegin(), end = _funcs.cend();
for (auto curIt = _funcs.cbegin(); curIt != end; ) {
lastIt = curIt++;
if (curIt == iterator) {
_funcs.erase_after(lastIt);
break;
}
}
}

void Clear() {
_funcs.clear();
}

void Invoke(Args... arg) {
if (Empty()) {
return;
}
for (auto& f : _funcs) {
f(std::forward<Args>(arg)...);
}
}

bool Empty() const {
return _funcs.empty();
}

void operator()(Args... arg) {
Invoke(std::forward<Args>(arg)...);
}

auto operator+=(Function func) {
return Add(func);
}

void operator-=(Iterator iterator) {
Remove(iterator);
}

operator bool() {
return !Empty();
}

private:
Container _funcs;

template<typename T, int... I>
auto _add(void(T::* func)(Args...), T& obj, std::integer_sequence<int, I...>) {
return Add(std::bind(func, std::ref(obj), Placeholder<I + 1>{}...));
}
};

使用

一些声明

1
2
3
4
5
6
7
8
9
10
11
12
using ArgType = const std::string&;

void PrintMessage(ArgType arg, char name) {
std::cout << arg << ": " << name << std::endl;
}

class Test {
public:
Test(char c) : name(c) {}
void f(ArgType var) { PrintMessage(var, name); }
char name;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Event<ArgType> onChanged;

Test t{ 't' };
const auto f = [](ArgType var) { PrintMessage(var, 'f'); };
const auto g = [](ArgType var) { PrintMessage(var, 'g'); };

auto tItor = onChanged.Add(&Test::f, t);
auto fItor = onChanged.Add(f);
auto gItor = onChanged.Add(g);
onChanged("Add all");

onChanged.Remove(fItor);
onChanged("Remove f");

onChanged.Clear();
onChanged("Clear");