-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy path329.md
152 lines (115 loc) · 4.06 KB
/
329.md
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<details open><summary>Info</summary><p>
* **Did you know about C++ allows to pass Pointer To Member Function via template parameter?**
* https://eel.is/c++draft/expr.mptr.oper#:operator,pointer_to_member
</p></details><details open><summary>Example</summary><p>
```cpp
struct header { int type{}; };
int main() {
std::cout << []<auto Ptr>(const auto& msg) {
return msg.*Ptr;
}.operator()<&header::type>(header{42}); // prints 42
}
```
> https://godbolt.org/z/cabhaoec1
</p></details><details open><summary>Puzzle</summary><p>
* **Can you implement a `dispatch` lambda expression which calls `::dispatch` function based on `header::type` and `msg::id`?**
```cpp
struct [[gnu::packed]] header {
int type{};
};
struct [[gnu::packed]] msg1 : header {
static constexpr auto id = 1;
int i{};
};
struct [[gnu::packed]] msg2 : header {
static constexpr auto id = 2;
float f{};
};
auto dispatch(std::ostream& out, const msg1& msg) { out << "msg1: " << msg.i; }
auto dispatch(std::ostream& out, const msg2& msg) { out << "msg2: " << msg.f; }
#include <https://raw.githubusercontent.com/boost-ext/ut/v1.1.9/include/boost/ut.hpp>
int main() {
using namespace boost::ut;
constexpr auto dispatch = /* TODO */;
"pointer to member dispatch not found"_test = [dispatch] {
const auto msg = msg1{};
const void* buffer = &msg;
std::stringstream out{};
dispatch.operator()<&header::type, msg1, msg2>(out, buffer);
expect(std::empty(out.str()));
};
"pointer to member dispatch found msg1"_test = [dispatch] {
const auto msg = msg1{msg1::id, 42};
const void* buffer = &msg;
std::stringstream out{};
dispatch.operator()<&header::type, msg1, msg2>(out, buffer);
expect(out.str() == std::string_view{"msg1: 42"});
};
"pointer to member dispatch found msg2"_test = [dispatch] {
const auto msg = msg2{msg2::id, 4.2};
const void* buffer = &msg;
std::stringstream out{};
dispatch.operator()<&header::type, msg1, msg2>(out, buffer);
expect(out.str() == std::string_view{"msg2: 4.2"});
};
}
```
> https://godbolt.org/z/q7n71h97z
</p></details><details><summary>Solutions</summary><p>
```cpp
constexpr auto dispatch = []<auto Type, typename... Msgs>(
auto& out, const auto& buffer) {
const auto type = static_cast<const header*>(buffer)->*Type;
(
[&]() {
switch (type) {
case Msgs::id:
const auto& msg = *static_cast<const Msgs*>(buffer);
::dispatch(out, msg);
break;
}
}(),
...);
};
```
> https://godbolt.org/z/7PMv1GE98
```cpp
constexpr auto dispatch = []<auto pm, class... Ts>(std::ostream& out,
const void* buffer) {
const auto type = static_cast<const header*>(buffer)->*pm;
std::variant<std::monostate, Ts...> v;
(
[&]() {
if (type == Ts::id) {
v = *static_cast<const Ts*>(buffer);
}
}(),
...);
return std::visit(overload{[&](auto&& msg) { ::dispatch(out, msg); },
[](std::monostate) {}},
v);
};
```
> https://godbolt.org/z/4Pz33K4Pq
```cpp
constexpr auto dispatch = []<auto Ptr, class... MessageTypes>(
auto& out, auto buffer) -> void {
const auto helper = [&]<class M>(const M* m) {
if (m->*Ptr == M::id) {
::dispatch(out, (M)(*reinterpret_cast<const M*>(buffer)));
}
};
(helper(reinterpret_cast<const MessageTypes*>(buffer)), ...);
};
```
> https://godbolt.org/z/sYGdEjq5q
```cpp
constexpr auto dispatch = [&]<auto Ptr, class... Ts>(std::stringstream& out,
const void* buffer) {
((reinterpret_cast<const header*>(buffer)->*Ptr == Ts::id &&
(::dispatch(out, *reinterpret_cast<const Ts*>(buffer)), true)) ||
...);
};
```
> https://godbolt.org/z/acvzx1re7
</p></details>