-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy path204.md
253 lines (199 loc) · 7.31 KB
/
204.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
<details open><summary>Info</summary><p>
* **Did you know that you can implement a compile-time map with C++?**
* https://www.boost.org/doc/libs/1_75_0/libs/mp11/doc/html/mp11.html#mp_map_find_m_k
</p></details><details open><summary>Example</summary><p>
```cpp
static_assert(std::is_same_v<void, boost::mp11::mp_map_find<std::tuple<>, int>>);
static_assert(std::is_same_v<void, boost::mp11::mp_map_find<std::tuple<std::pair<int, double>>, double>>);
static_assert(std::is_same_v<std::pair<int, double>, boost::mp11::mp_map_find<std::tuple<std::pair<int, double>>, int>>);
```
> https://godbolt.org/z/zh7488
</p></details><details open><summary>Puzzle</summary><p>
* **Can you implement a user-friendly `make` routine which creates a given type with named parameters by leveraging a compile-time map?**
```cpp
template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) { /*TODO*/ }
template<class TSize, class TValue>
struct foo {};
static_assert(std::is_same_v<foo<int, int>, decltype(make<foo>("size"_arg = int{}, "value"_arg = int{}))>);
static_assert(std::is_same_v<foo<int, int>, decltype(make<foo>("value"_arg = int{}, "size"_arg = int{}))>);
static_assert(std::is_same_v<foo<short, double>, decltype(make<foo>("size"_arg = short{}, "value"_arg = double{}))>);
```
> https://godbolt.org/z/465xzr
</p></details><details><summary>Solutions</summary><p>
```cpp
template <auto... Cs>
struct Arg {
template <typename T>
constexpr auto operator=(const T&) { return std::pair<Arg<Cs...>, T>{}; }
};
template <typename T, T... Cs>
constexpr auto operator""_arg() {
return Arg<Cs...>{};
}
template<template<typename...> typename T, typename... Ts>
constexpr auto make(Ts...) {
using map_t = boost::mp11::mp_list<Ts...>;
using size_t = typename boost::mp11::mp_map_find<map_t, decltype("size"_arg)>::second_type;
using value_t = typename boost::mp11::mp_map_find<map_t, decltype("value"_arg)>::second_type;
return T<size_t, value_t>{};
}
```
> https://godbolt.org/z/K6eznr
```cpp
template< typename K>
struct KeyValue
{
template< typename V>
auto operator = ( V )
{
return std::pair<K,V>{};
}
};
template<std::size_t N>
struct StaticString
{
char str[N]{};
constexpr StaticString ( char const(&p_str)[N] )
{
std::ranges::copy(p_str, str);
};
template<std::size_t M>
constexpr bool operator == ( char const(&p_str)[M] ) const
{
return std::ranges::equal( p_str, str);
}
};
struct value_type{};
struct size_type{};
template<StaticString ss>
constexpr auto operator""_arg()
{
if constexpr(ss == "value")
return KeyValue<value_type>{};
else if constexpr( ss == "size" )
return KeyValue<size_type>{};
}
template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
return T< typename boost::mp11::mp_map_find<std::tuple<Ts...>, size_type>::second_type
, typename boost::mp11::mp_map_find<std::tuple<Ts...>, value_type>::second_type
>{};
}
```
> https://godbolt.org/z/s9WMoj
```cpp
template<auto Size>
struct fixed_string {
char data[Size + 1]{};
static constexpr auto size = Size;
constexpr explicit(false) fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
constexpr explicit(false) operator std::string_view() const { return {data, Size}; }
};
template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;
template<auto...>
struct arg {
template<class T> constexpr auto operator=(const T& t) const { return std::pair<arg, T>{*this, t}; }
};
template<fixed_string Str> constexpr auto operator""_arg() {
return []<auto... Ns>(std::index_sequence<Ns...>) {
return arg<Str.data[Ns]...>{};
}(std::make_index_sequence<Str.size>{});
}
template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
using types_t = boost::mp11::mp_list<Ts...>;
using size_t = typename boost::mp11::mp_map_find<types_t, decltype("siize"_arg)>::second_type;
using value_t = typename boost::mp11::mp_map_find<types_t, decltype("value"_arg)>::second_type;
return T<size_t, value_t>{};
}
```
> https://godbolt.org/z/94qhrM
```cpp
template<char... Cs> struct Name;
template<typename T, char ... Cs>
struct NamedType {
using name = Name<Cs...>;
using type = T;
};
template<char ...Cs>
struct Name {
template<typename T> NamedType<T, Cs...> operator=(T) { return {}; }
};
template<typename Tchar, Tchar ... Cs> constexpr Name<Cs...> operator"" _arg() { return {}; }
template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
using map = std::tuple<std::pair<typename Ts::name, typename Ts::type>...>;
using value = boost::mp11::mp_map_find<map, Name<'v','a','l','u','e'>>::second_type;
using size = boost::mp11::mp_map_find<map, Name<'s','i','z','e'>>::second_type;
return T<size,value>{};
}
```
> https://godbolt.org/z/YK8GPW
```cpp
namespace detail
{
using boost::mp11::mp_second;
using boost::mp11::mp_map_find;
template<auto Size>
struct fixed_string {
using type = fixed_string;
char data[Size + 1]{};
static constexpr auto size = Size;
constexpr fixed_string() = default;
constexpr fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
};
template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;
template<auto...>
struct arg
{
template <class T>
constexpr std::pair<arg, T> operator=(T&& value) const { return {*this, value}; }
};
template<template<class...> class T>
struct class_template {};
template<template<class...> class T, template<class... Ts> class M>
concept is_same_class_template_v = std::is_same_v<class_template<T>, class_template<M>>;
namespace literal
{
template<fixed_string Fs> constexpr auto operator""_arg()
{
return []<auto... Ns>(std::index_sequence<Ns...>)
{
return arg<Fs.data[Ns]...>{};
}(std::make_index_sequence<Fs.size>{});
}
template<fixed_string Fs> constexpr auto make_arg()
{
return []<auto... Ns>(std::index_sequence<Ns...>)
{
return arg<Fs.data[Ns]...>{};
}(std::make_index_sequence<Fs.size>{});
}
}
// for simplifying user-defined declarations below
namespace helpers
{
template<template<class...> class T, template<class... Ts> class M>
concept match = is_same_class_template_v<T, M>;
template<template <class...> class T, class L, fixed_string... Ks>
using unpack = T<typename mp_map_find<L, decltype(literal::make_arg<Ks>())>::second_type...>;
template<class... Ts>
using pack = std::tuple<Ts...>;
}
}
using namespace detail::literal;
using namespace detail::helpers;
// user-defined template classes
template<class TSize, class TValue>
struct foo {};
template<class TOne, class TTwo>
struct bar {};
// user-defined declarations to define unpacking order of named arguments for template classes
template<template<class...> class T, class... Ts> requires match<T, foo>
constexpr unpack<T, pack<Ts...>, "size", "value"> make(Ts...) { return {}; }
template<template<class...> class T, class... Ts> requires match<T, bar>
constexpr unpack<T, pack<Ts...>, "one", "two"> make(Ts...) { return {}; }
```
> https://godbolt.org/z/e15nzv
</p></details>