-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy path353.md
99 lines (76 loc) · 2.61 KB
/
353.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
<details open><summary>Info</summary><p>
* **Did you know that the underlying visit implementation of std::visit has changed since GCC12+, Clang15+?**
* https://eel.is/c++draft/variant.mod#lib:emplace,variant
</p></details><details open><summary>Example</summary><p>
```cpp
template<class... Ts>
struct inc {
std::variant<Ts...> v{};
auto operator++() {
std::visit([&](auto& v) { ++v; }, v);
}
template<class T>
operator T() const {
T result{};
std::visit(
overloaded{
[&](T v) { result = v; },
[](auto&&) {}
}
, v);
return result;
}
};
auto visit(std::int16_t size, std::int32_t iterations) {
auto it = inc<std::int8_t, std::int16_t, std::int32_t>{size};
for (auto i = 0; i < iterations; ++i, ++it)
;
return std::int16_t(it);
}
```
> https://godbolt.org/z/1813rceKv
</p></details><details open><summary>Puzzle</summary><p>
* **Can you implement different versions of std::visit dispatching and compare its performance?
* generated switch case
* jump table
* fold expression
* if/else
* generted goto
* ...
```cpp
constexpr auto visit(auto&& f, auto&& v); // TODO
```
> https://godbolt.org/z/eac6YarnG
</p></details>
</p></details><details><summary>Solutions</summary><p>
```cpp
template<class F, class V, class R, std::size_t N, std::size_t Size>
constexpr auto visit_impl([[maybe_unused]] F&& f, [[maybe_unused]] V&& v) -> R {
if constexpr (N < Size) {
switch (v.index()) {
default:
return visit_impl<F, V, R, N+1, Size>(std::forward<F>(f), std::forward<V>(v));
case N:
return std::forward<F>(f)(std::get<N>(std::forward<V>(v)));
}
} else {
__builtin_unreachable();
}
}
template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<Ts...>&&) ->
std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;
template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<std::monostate, Ts...>&&) ->
std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;
template<class F, class V>
constexpr decltype(auto) visit(F&& f, V&& v) {
using variant_t = std::remove_const_t<std::remove_reference_t<V>>;
constexpr auto size = std::variant_size_v<variant_t>;
static_assert(size > 0, "Empty variant is not supported!");
using result_t = decltype(result_type<F, V>(std::declval<variant_t>()));
return visit_impl<F, V, result_t, 0u, size>(std::forward<F>(f), std::forward<V>(v));
}
```
> https://godbolt.org/z/YPqGzKP95
</p></details>