警告
本文最后更新于 2024-05-01,文中内容可能已过时。
Curriously Recursive Template Method(CRTP
) 一种是实现了编译期多态(静态多态)的方法,相比于虚函数(virtual
)跳过了虚表vtable
查找,提供了比动态多态(运行时多态)更好的性能。
demo
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
|
#include <functional>
#include <vector>
#include <iostream>
#include <unordered_map>
#include <string>
#include <utility>
#include <variant>
using namespace std;
template<typename T>
struct B
{
public:
using cb_t = std::function<void()>;
B() { _cbs.reserve(10); }
virtual ~B() { cout << "~B" << endl; }
void foo() noexcept
{
this->get()->foo_impl();
for (const auto& cb : _cbs)
cb();
}
void register_cb(cb_t cb) noexcept
{
_cbs.push_back(cb);
}
private:
T* get() noexcept { return static_cast<T*>(this); }
std::vector<cb_t> _cbs;
};
struct D1: public B<D1>
{
~D1() { cout << "~D1" << endl; }
void foo_impl() noexcept { cout << "D1:foo_impl" << endl; }
};
struct D2: public B<D2>
{
~D2() { cout << "~D2" << endl; }
void foo_impl() noexcept { cout << "D2:foo_impl" << endl; }
};
template<typename T>
void execute(B<T>* e)
{
e->foo();
}
int main()
{
B<D1>* d1 = new D1;
d1->register_cb([]()
{
cout << "[d1] cb called" << endl;
});
B<D2>* d2 = new D2;
d2->register_cb([]()
{
cout << "[d2] cb called" << endl;
});
std::unordered_map<std::string, std::variant<B<D1>*, B<D2>*>> m;
m["d1"] = d1;
m["d2"] = d2;
//use variant
{
auto d = std::get<B<D1>*>(m["d1"]);
d->foo();
}
//use variant
{
auto d = std::get<B<D2>*>(m["d2"]);
d->foo();
}
//policy-based ctx
execute(d1);
execute(d2);
delete d1;
delete d2;
return 0;
}
|
运行结果
1
2
3
4
5
6
|
D1:foo_impl
[d1] cb called
D2:foo_impl
[d2] cb called
~D1
~D2
|
Tips
- cb 需要绑定
lambda
表达式的引用或者函数指针,编译器有可能认为这是同一个代码段,导致上面的 cb 一直打印 d2 cb