Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /* Copyright 2023 Jack A Bernard Jr. | |||
2 | * | |||
3 | * Licensed under the Apache License, Version 2.0 (the License); | |||
4 | * you may not use this file except in compliance with the License. | |||
5 | * You may obtain a copy of the License at | |||
6 | * | |||
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
8 | * | |||
9 | * Unless required by applicable law or agreed to in writing, software | |||
10 | * distributed under the License is distributed on an AS IS BASIS, | |||
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
12 | * See the License for the specific language governing permissions and | |||
13 | * limitations under the License. | |||
14 | */ | |||
15 | ||||
16 | #ifndef SUMTY_VARIANT_HPP | |||
17 | #define SUMTY_VARIANT_HPP | |||
18 | ||||
19 | #include "sumty/detail/fwd.hpp" // IWYU pragma: export | |||
20 | #include "sumty/detail/traits.hpp" // IWYU pragma: export | |||
21 | #include "sumty/detail/utils.hpp" | |||
22 | #include "sumty/detail/variant_impl.hpp" // IWYU pragma: export | |||
23 | #include "sumty/exceptions.hpp" | |||
24 | #include "sumty/utils.hpp" | |||
25 | ||||
26 | #include <array> | |||
27 | #include <cstddef> | |||
28 | #include <functional> | |||
29 | #include <initializer_list> | |||
30 | #include <type_traits> | |||
31 | #include <utility> | |||
32 | ||||
33 | namespace sumty { | |||
34 | ||||
35 | namespace detail { | |||
36 | ||||
37 | template <typename T> | |||
38 | struct variant_size_helper; | |||
39 | ||||
40 | template <typename... T> | |||
41 | struct variant_size_helper<variant<T...>> : std::integral_constant<size_t, sizeof...(T)> {}; | |||
42 | ||||
43 | template <typename... T> | |||
44 | struct variant_size_helper<const variant<T...>> | |||
45 | : std::integral_constant<size_t, sizeof...(T)> {}; | |||
46 | ||||
47 | template <size_t I, typename T> | |||
48 | struct variant_alternative_helper; | |||
49 | ||||
50 | template <size_t I, typename... T> | |||
51 | struct variant_alternative_helper<I, variant<T...>> { | |||
52 | using type = detail::select_t<I, T...>; | |||
53 | }; | |||
54 | ||||
55 | template <size_t I, typename... T> | |||
56 | struct variant_alternative_helper<I, const variant<T...>> | |||
57 | : variant_alternative_helper<I, variant<T...>> {}; | |||
58 | ||||
59 | template <size_t IDX, typename V, typename U> | |||
60 | // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) | |||
61 | 52 | constexpr decltype(auto) jump_table_entry(V&& visitor, U&& var) { | ||
62 | if constexpr (std::is_void_v<decltype(std::forward<U>(var)[sumty::index<IDX>])>) { | |||
63 | 12 | return std::invoke(std::forward<V>(visitor), void_v); | ||
64 | } else { | |||
65 | 40 | return std::invoke(std::forward<V>(visitor), | ||
66 | 80 | std::forward<U>(var)[sumty::index<IDX>]); | ||
67 | } | |||
68 | } | |||
69 | ||||
70 | template <typename V, typename U, size_t... IDX> | |||
71 | consteval auto make_jump_table([[maybe_unused]] std::index_sequence<IDX...> seq) { | |||
72 | using ret_t = decltype(jump_table_entry<0>(std::declval<V&&>(), std::declval<U&&>())); | |||
73 | return std::array<ret_t (*)(V&&, U&&), sizeof...(IDX)>{ | |||
74 | {&jump_table_entry<IDX, V, U>...}}; | |||
75 | } | |||
76 | ||||
77 | template <typename V, typename U, typename... T> | |||
78 | consteval auto make_jump_table() noexcept { | |||
79 | return make_jump_table<V, U>(std::make_index_sequence<sizeof...(T)>{}); | |||
80 | } | |||
81 | ||||
82 | template <typename V, typename U, typename... T> | |||
83 | static constexpr auto jump_table = make_jump_table<V, U, T...>(); | |||
84 | ||||
85 | template <typename V, typename U, typename... T> | |||
86 | // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) | |||
87 | 52 | constexpr decltype(auto) visit_impl(V&& visitor, U&& var) { | ||
88 | 52 | return jump_table<V, U, T...>[var.index()](std::forward<V>(visitor), | ||
89 | 52 | std::forward<U>(var)); | ||
90 | } | |||
91 | ||||
92 | template <size_t IDX, typename V> | |||
93 | struct alternative_info { | |||
94 | static inline constexpr size_t index = IDX; | |||
95 | using type = typename variant_alternative_helper<IDX, V>::type; | |||
96 | }; | |||
97 | ||||
98 | template <size_t IDX, typename V, typename U> | |||
99 | // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) | |||
100 | 70 | constexpr decltype(auto) informed_jump_table_entry(V&& visitor, [[maybe_unused]] U&& var) { | ||
101 | if constexpr (std::is_void_v<decltype(std::forward<U>(var)[sumty::index<IDX>])>) { | |||
102 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | return std::invoke(std::forward<V>(visitor), void_v, | |
103 | 12 | alternative_info<IDX, std::remove_cvref_t<U>>{}); | ||
104 | } else { | |||
105 |
2/3✓ Branch 1 taken 3 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
58 | return std::invoke(std::forward<V>(visitor), | |
106 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
58 | std::forward<U>(var)[sumty::index<IDX>], | |
107 | 58 | alternative_info<IDX, std::remove_cvref_t<U>>{}); | ||
108 | } | |||
109 | } | |||
110 | ||||
111 | template <typename V, typename U, size_t... IDX> | |||
112 | consteval auto make_informed_jump_table([[maybe_unused]] std::index_sequence<IDX...> seq) { | |||
113 | using ret_t = | |||
114 | decltype(informed_jump_table_entry<0>(std::declval<V&&>(), std::declval<U&&>())); | |||
115 | return std::array<ret_t (*)(V&&, U&&), sizeof...(IDX)>{ | |||
116 | {&informed_jump_table_entry<IDX, V, U>...}}; | |||
117 | } | |||
118 | ||||
119 | template <typename V, typename U, typename... T> | |||
120 | consteval auto make_informed_jump_table() noexcept { | |||
121 | return make_informed_jump_table<V, U>(std::make_index_sequence<sizeof...(T)>{}); | |||
122 | } | |||
123 | ||||
124 | template <typename V, typename U, typename... T> | |||
125 | static constexpr auto informed_jump_table = make_informed_jump_table<V, U, T...>(); | |||
126 | ||||
127 | template <typename V, typename U, typename... T> | |||
128 | // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) | |||
129 | 70 | constexpr decltype(auto) visit_informed_impl(V&& visitor, U&& var) { | ||
130 | 70 | return informed_jump_table<V, U, T...>[var.index()](std::forward<V>(visitor), | ||
131 | 70 | std::forward<U>(var)); | ||
132 | } | |||
133 | ||||
134 | } // namespace detail | |||
135 | ||||
136 | /// @class variant variant.hpp <sumty/variant.hpp> | |||
137 | /// @brief General discriminated union | |||
138 | /// | |||
139 | /// @details | |||
140 | /// @ref variant is the fundamental sum type of sumty. @ref option, @ref | |||
141 | /// result, and @ref error_set are defined in terms of @ref variant. | |||
142 | /// | |||
143 | /// @ref variant is very similar to `std::variant`, but it does have some | |||
144 | /// key differences. Most notably, @ref variant does not support type-based | |||
145 | /// alternative selection unless all alternatives have a distinct type. For | |||
146 | /// example, `std::variant` will allow the code shown below, but @ref variant | |||
147 | /// will not. | |||
148 | /// | |||
149 | /// ```cpp | |||
150 | /// std::variant<int, int> v = 42; | |||
151 | /// ``` | |||
152 | /// | |||
153 | /// Any such functionality from `std::variant` that is similarly ambiguous to | |||
154 | /// the reader is disallowed by @ref variant. Otherwise, the interface provided | |||
155 | /// by @ref variant is identical to `std::variant`, but with some additional | |||
156 | /// functions available. | |||
157 | /// | |||
158 | /// Another key difference from `std::variant` is that @ref variant allows | |||
159 | /// alternatives to have `void` and references (both lvalue and rvalue) as | |||
160 | /// types. When using an lvalue reference as an alternative type, copy and move | |||
161 | /// semantics applied to the @ref variant are the same as a raw pointer (both | |||
162 | /// trivial), instead of immovability of lvalue references. | |||
163 | /// | |||
164 | /// A more subtle, but important, difference from `std::variant` is that @ref | |||
165 | /// variant makes size optimizations for several special cases. These special | |||
166 | /// cases revolve around alternatives with types that are lvalue references, | |||
167 | /// `void`, and empty types (such as `std::monostate`). | |||
168 | /// | |||
169 | /// `void` and empty types need not occupy any memory at runtime, despite the | |||
170 | /// fact that `sizeof(<empty-type>) == 1` in C++. A @ref variant consisting | |||
171 | /// entirely of alternatives with types that are `void` or empty types only | |||
172 | /// takes up enough space to store a discriminant, which is always the smallest | |||
173 | /// possible integral type necessary to store the value `N - 1`, where `N` is | |||
174 | /// the number of alternatives. Here are some examples: | |||
175 | /// | |||
176 | /// ```cpp | |||
177 | /// struct empty_t {}; | |||
178 | /// | |||
179 | /// assert(std::is_empty_v<variant<void>>); | |||
180 | /// | |||
181 | /// assert(std::is_empty_v<variant<empty_t>>); | |||
182 | /// | |||
183 | /// assert(sizeof(variant<void, empty_t>) == sizeof(bool)); | |||
184 | /// | |||
185 | /// assert(sizeof(variant<empty_t, ...>) // repeated 256 times | |||
186 | /// == sizeof(uint8_t)); | |||
187 | /// | |||
188 | /// assert(sizeof(variant<empty_t, ...>) // repeated 257 times | |||
189 | /// == sizeof(uint16_t)); | |||
190 | /// ``` | |||
191 | /// | |||
192 | /// lvalue references have the invariant that the underlying pointer is not | |||
193 | /// null. This means in cases where there are only two alternatives, with one | |||
194 | /// being an lvalue reference and the other being `void` or an empty type, null | |||
195 | /// and non-null can be used as the discriminanting values instead of having a | |||
196 | /// separate discriminant. Here are some more examples: | |||
197 | /// | |||
198 | /// ```cpp | |||
199 | /// struct empty_t {}; | |||
200 | /// | |||
201 | /// assert(sizeof(variant<int&, void>) == sizeof(int*)); | |||
202 | /// | |||
203 | /// assert(sizeof(variant<empty_t, int&>) == sizeof(int*)); | |||
204 | /// ``` | |||
205 | /// | |||
206 | /// @tparam T @ref variant alternative types | |||
207 | template <typename... T> | |||
208 | class variant : detail::variant_impl<void, T...> { | |||
209 | private: | |||
210 | 802 | [[nodiscard]] constexpr detail::variant_impl<void, T...>& data_() & noexcept { | ||
211 | 802 | return *static_cast<detail::variant_impl<void, T...>*>(this); | ||
212 | } | |||
213 | ||||
214 | 1492 | [[nodiscard]] constexpr const detail::variant_impl<void, T...>& data_() | ||
215 | const& noexcept { | |||
216 | 1492 | return *static_cast<const detail::variant_impl<void, T...>*>(this); | ||
217 | } | |||
218 | ||||
219 | [[nodiscard]] constexpr detail::variant_impl<void, T...>& data_() && { | |||
220 | return std::move(*static_cast<detail::variant_impl<void, T...>*>(this)); | |||
221 | } | |||
222 | ||||
223 | [[nodiscard]] constexpr const detail::variant_impl<void, T...>& data_() const&& { | |||
224 | return std::move(*static_cast<const detail::variant_impl<void, T...>*>(this)); | |||
225 | } | |||
226 | ||||
227 | template <size_t IDX, typename U> | |||
228 | 16 | [[nodiscard]] constexpr bool holds_alt_impl() const noexcept { | ||
229 | if constexpr (IDX == sizeof...(T)) { | |||
230 | 2 | return false; | ||
231 | } else if constexpr (std::is_same_v<detail::select_t<IDX, T...>, U>) { | |||
232 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3 times.
|
10 | if (index() == IDX) { |
233 | 4 | return true; | ||
234 | } else { | |||
235 | 6 | return holds_alt_impl<IDX + 1, U>(); | ||
236 | } | |||
237 | } else { | |||
238 | 4 | return holds_alt_impl<IDX + 1, U>(); | ||
239 | } | |||
240 | } | |||
241 | ||||
242 | template <size_t IDX> | |||
243 | struct emplace_construct_t {}; | |||
244 | ||||
245 | template <size_t IDX, typename U> | |||
246 | requires(detail::traits<detail::select_t<IDX, T...>>::template is_constructible<U>) | |||
247 | 18 | constexpr explicit variant([[maybe_unused]] emplace_construct_t<IDX> tag, U&& value) | ||
248 | 18 | : variant(std::in_place_index<IDX>, std::forward<U>(value)) {} | ||
249 | ||||
250 | template <size_t IDX, typename U> | |||
251 | requires(!detail::traits<detail::select_t<IDX, T...>>::template is_constructible<U>) | |||
252 | 8 | constexpr explicit variant([[maybe_unused]] emplace_construct_t<IDX> tag, U&& value) | ||
253 | 8 | : variant(emplace_construct_t<IDX + 1>{}, std::forward<U>(value)) {} | ||
254 | ||||
255 | // NOLINTNEXTLINE(hicpp-explicit-conversions) | |||
256 | 58 | constexpr variant([[maybe_unused]] detail::uninit_t tag) noexcept | ||
257 | 58 | : detail::variant_impl<void, T...>(tag) {} | ||
258 | ||||
259 | template <size_t I, typename... Args> | |||
260 | 58 | constexpr void uninit_emplace(Args&&... args) { | ||
261 | 58 | data_().template uninit_emplace<I>(std::forward<Args>(args)...); | ||
262 | 58 | } | ||
263 | ||||
264 | friend class error_set<T...>; | |||
265 | ||||
266 | template <typename, typename> | |||
267 | friend class result; | |||
268 | ||||
269 | public: | |||
270 | /// @brief Default constructor | |||
271 | /// | |||
272 | /// @details | |||
273 | /// Initializes the @ref variant such that it contains a default | |||
274 | /// constructed value of the first (index 0) alternative. | |||
275 | /// | |||
276 | /// The first alternative *must* be default constructible for this | |||
277 | /// constructor to participate in overload resoltuion, but no other | |||
278 | /// alternatives need be default constructible. | |||
279 | /// | |||
280 | /// ## Example | |||
281 | /// ```cpp | |||
282 | /// variant<int, bool, int> v; | |||
283 | /// | |||
284 | /// assert(holds_alternative<int>(v)); | |||
285 | /// | |||
286 | /// assert(v.index() == 0); | |||
287 | /// | |||
288 | /// assert(get<0>(v) == int{}); | |||
289 | /// ``` | |||
290 | 162 | constexpr variant() | ||
291 | #ifndef DOXYGEN | |||
292 | noexcept(detail::traits<detail::first_t<T...>>::is_nothrow_default_constructible) | |||
293 | requires(detail::traits<detail::first_t<T...>>::is_default_constructible) | |||
294 | = default; | |||
295 | #else | |||
296 | CONDITIONALLY_NOEXCEPT; | |||
297 | #endif | |||
298 | ||||
299 | /// @brief Copy constructor | |||
300 | /// | |||
301 | /// @details | |||
302 | /// A new @ref variant is initialized such that it contains a copy | |||
303 | /// constructed instance of the alternative contained in the source @ref | |||
304 | /// variant. If the source @ref variant has more than one alternative of | |||
305 | /// the same type, the new @ref variant will contain the alternative of the | |||
306 | /// same index. | |||
307 | /// | |||
308 | /// All alternative types *must* be copy constructible for this constructor | |||
309 | /// to participate in overload resolution. | |||
310 | /// | |||
311 | /// ## Example | |||
312 | /// ```cpp | |||
313 | /// variant<int, bool, int> v1{std::in_place_index<2>, 42}; | |||
314 | /// | |||
315 | /// variant<int, bool, int> v2{v1}; | |||
316 | /// | |||
317 | /// assert(holds_alternative<int>(v2)); | |||
318 | /// | |||
319 | /// assert(v2.index() == 2); | |||
320 | /// | |||
321 | /// assert(get<2>(v2) == 42); | |||
322 | /// ``` | |||
323 | 22 | constexpr variant(const variant&) | ||
324 | #ifndef DOXYGEN | |||
325 | requires(true && ... && detail::traits<T>::is_copy_constructible) | |||
326 | = default; | |||
327 | #else | |||
328 | ; | |||
329 | #endif | |||
330 | ||||
331 | /// @brief Move constructor | |||
332 | /// | |||
333 | /// @details | |||
334 | /// A new @ref variant is initialized such that it contains a move | |||
335 | /// constructed instance of the alternative contained in the source @ref | |||
336 | /// variant. If the source @ref vairant has more than one alternative of | |||
337 | /// the same type, the new @ref variant will contain the alternative of the | |||
338 | /// same index. | |||
339 | /// | |||
340 | /// All alternative types *must* be move constructible for this constructor | |||
341 | /// to participate in overload resolution. | |||
342 | /// | |||
343 | /// The source variant will continue to contain an instance of the same | |||
344 | /// alternative, but the value of the alternative after being moved depends | |||
345 | /// on the move constructor of the type. In general, moved values are said | |||
346 | /// to be in a valid, but unspecified, state. | |||
347 | /// | |||
348 | /// ## Example | |||
349 | /// ```cpp | |||
350 | /// variant<int, bool, int> v1{std::in_place_index<2>, 42}; | |||
351 | /// | |||
352 | /// variant<int, bool, int> v2{std::move(v1)}; | |||
353 | /// | |||
354 | /// assert(holds_alternative<int>(v2)); | |||
355 | /// | |||
356 | /// assert(v2.index() == 2); | |||
357 | /// | |||
358 | /// assert(get<2>(v2) == 42); | |||
359 | /// ``` | |||
360 | 6 | constexpr variant(variant&&) | ||
361 | #ifndef DOXYGEN | |||
362 | noexcept((true && ... && detail::traits<T>::is_nothrow_move_constructible)) | |||
363 | requires(true && ... && detail::traits<T>::is_move_constructible) | |||
364 | = default; | |||
365 | #else | |||
366 | ; | |||
367 | #endif | |||
368 | ||||
369 | /// @brief Index emplacement constructor | |||
370 | /// | |||
371 | /// @details | |||
372 | /// A new @ref variant is initialized such that it contains a newly | |||
373 | /// constructed instance of the alternative with the specified index. | |||
374 | /// The arguments following `inplace` are forwarded directly to the | |||
375 | /// constructor of the alternative type. | |||
376 | /// | |||
377 | /// Given that `U` is the type of the alternative at the specified index, | |||
378 | /// this constructor is always valid as long as `U` is constructible with | |||
379 | /// the arguments, `std::forward<Args>(args)...`. | |||
380 | /// | |||
381 | /// ## Example | |||
382 | /// ```cpp | |||
383 | /// variant<int, std::string> v{std::in_place_index<1>, 5, 'a'}; | |||
384 | /// | |||
385 | /// assert(holds_alternative<std::string>(v)); | |||
386 | /// | |||
387 | /// assert(v.index() == 1); | |||
388 | /// | |||
389 | /// assert(get<1>(v) == "aaaaa"); | |||
390 | /// ``` | |||
391 | /// | |||
392 | /// @param inplace Constructor tag that specifies the alternative index. | |||
393 | /// @param args Arguments used to construct the alternative. | |||
394 | template <size_t IDX, typename... Args> | |||
395 | #ifndef DOXYGEN | |||
396 | explicit(sizeof...(Args) == 0) | |||
397 | #else | |||
398 | CONDITIONALLY_EXPLICIT | |||
399 | #endif | |||
400 | // NOLINTNEXTLINE(hicpp-explicit-conversions) | |||
401 | 236 | constexpr variant(std::in_place_index_t<IDX> inplace, Args&&... args) | ||
402 | 236 | : detail::variant_impl<void, T...>(inplace, std::forward<Args>(args)...) { | ||
403 | 236 | } | ||
404 | ||||
405 | /// @brief Index emplacement constructor with `std::initializer_list` | |||
406 | /// | |||
407 | /// @details | |||
408 | /// A new @ref variant is initialized such that it contains a newly | |||
409 | /// constructed instance of the alternative with the specified index. | |||
410 | /// The arguments following `inplace` are forwarded directly to the | |||
411 | /// constructor of the alternative type. | |||
412 | /// | |||
413 | /// Given that `U` is the type of the alternative at the specified index, | |||
414 | /// this constructor is always valid as long as `U` is constructible with | |||
415 | /// the arguments, `init, std::forward<Args>(args)...`. | |||
416 | /// | |||
417 | /// ## Example | |||
418 | /// ```cpp | |||
419 | /// variant<int, std::vector<int>> v{ | |||
420 | /// std::in_place_index<1>, | |||
421 | /// {1, 2, 3, 4, 5}}; | |||
422 | /// | |||
423 | /// assert(holds_alternative<std::vector<int>>(v)); | |||
424 | /// | |||
425 | /// assert(v.index() == 1); | |||
426 | /// | |||
427 | /// assert(get<1>(v).size() == 5); | |||
428 | /// ``` | |||
429 | /// | |||
430 | /// @param inplace Constructor tag that specifies the alternative index. | |||
431 | /// @param init Initializer list forwarded to the alternative constructor | |||
432 | /// @param args Additional arguments used to construct the alternative. | |||
433 | template <size_t IDX, typename U, typename... Args> | |||
434 | 1 | constexpr variant(std::in_place_index_t<IDX> inplace, | ||
435 | std::initializer_list<U> init, | |||
436 | Args&&... args) | |||
437 | 1 | : detail::variant_impl<void, T...>(inplace, init, std::forward<Args>(args)...) {} | ||
438 | ||||
439 | /// @brief Type emplacement constructor | |||
440 | /// | |||
441 | /// @details | |||
442 | /// A new @ref variant is initialized such that it contains a newly | |||
443 | /// constructed instance of the alternative with the specified type. | |||
444 | /// The arguments following `inplace` are forwarded directory to the | |||
445 | /// constructor of the alternative type. | |||
446 | /// | |||
447 | /// This constructor only participates in overload resolution if the | |||
448 | /// alternative type, `U`, is unique among all alternatives of the @ref | |||
449 | /// variant. That is, `variant<A, B, A>`, cannot use this constructor to | |||
450 | /// initialize an alternative of type `A`, but it could use this | |||
451 | /// constructor to initialize the alternative of type `B`. This constraint | |||
452 | /// is imposed to prevent ambiguity to the reader. Use the index based | |||
453 | /// emplacement constructor instead to initialize the alternative of type | |||
454 | /// `A`. | |||
455 | /// | |||
456 | /// ## Example | |||
457 | /// ```cpp | |||
458 | /// variant<int, std::string> v{ | |||
459 | /// std::in_place_type<std::string>, | |||
460 | /// 5, 'a'}; | |||
461 | /// | |||
462 | /// assert(holds_alternative<std::string>(v)); | |||
463 | /// | |||
464 | /// assert(v.index() == 1); | |||
465 | /// | |||
466 | /// assert(get<1>(v) == "aaaaa"); | |||
467 | /// ``` | |||
468 | template <typename U, typename... Args> | |||
469 | #ifndef DOXYGEN | |||
470 | requires(detail::is_unique_v<U, T...>) | |||
471 | explicit(sizeof...(Args) == 0) | |||
472 | #else | |||
473 | CONDITIONALLY_EXPLICIT | |||
474 | #endif | |||
475 | // NOLINTNEXTLINE(hicpp-explicit-conversions) | |||
476 | 4 | constexpr variant([[maybe_unused]] std::in_place_type_t<U> inplace, Args&&... args) | ||
477 | : detail::variant_impl<void, T...>(std::in_place_index<detail::index_of_v<U, T...>>, | |||
478 | 4 | std::forward<Args>(args)...) { | ||
479 | 4 | } | ||
480 | ||||
481 | /// @brief Type emplacement constructor with `std::initializer_list` | |||
482 | /// | |||
483 | /// @details | |||
484 | /// A new @ref variant is initialized such that it contains a newly | |||
485 | /// constructed instance of the alternative with the specified type. | |||
486 | /// The arguments following `inplace` are forwarded directory to the | |||
487 | /// constructor of the alternative type. | |||
488 | /// | |||
489 | /// This constructor only participates in overload resolution if the | |||
490 | /// alternative type, `U`, is unique among all alternatives of the @ref | |||
491 | /// variant. That is, `variant<A, B, A>`, cannot use this constructor to | |||
492 | /// initialize an alternative of type `A`, but it could use this | |||
493 | /// constructor to initialize the alternative of type `B`. This constraint | |||
494 | /// is imposed to prevent ambiguity to the reader. Use the index based | |||
495 | /// emplacement constructor instead to initialize the alternative of type | |||
496 | /// `A`. | |||
497 | /// | |||
498 | /// ## Example | |||
499 | /// ```cpp | |||
500 | /// variant<int, std::vector<int>> v{ | |||
501 | /// std::in_place_type<std::vector<int>>, | |||
502 | /// {1, 2, 3, 4, 5}}; | |||
503 | /// | |||
504 | /// assert(holds_alternative<std::vector<int>>(v)); | |||
505 | /// | |||
506 | /// assert(v.index() == 1); | |||
507 | /// | |||
508 | /// assert(get<1>(v).size() == 5); | |||
509 | /// ``` | |||
510 | template <typename U, typename V, typename... Args> | |||
511 | #ifndef DOXYGEN | |||
512 | requires(detail::is_unique_v<U, T...>) | |||
513 | #endif | |||
514 | 1 | constexpr variant([[maybe_unused]] std::in_place_type_t<U> inplace, | ||
515 | std::initializer_list<V> init, | |||
516 | Args&&... args) | |||
517 | : detail::variant_impl<void, T...>(std::in_place_index<detail::index_of_v<U, T...>>, | |||
518 | init, | |||
519 | 1 | std::forward<Args>(args)...) { | ||
520 | 1 | } | ||
521 | ||||
522 | /// @brief Forwarding constructor | |||
523 | /// | |||
524 | /// @details | |||
525 | /// A new @ref variant is initialized such that an alternative is | |||
526 | /// constructed in place with the provided value as the constructor | |||
527 | /// argument. | |||
528 | /// | |||
529 | /// To avoid ambiguity to the reader, this constructor only participates | |||
530 | /// in overload resolution when there is only one alternative that could | |||
531 | /// possibly be constructed from the value. | |||
532 | /// | |||
533 | /// This constructor is `explicit` if the value is not implicitly | |||
534 | /// convertible to the target alternative type. | |||
535 | /// | |||
536 | /// This constructor should be avoided in generic code, because some @ref | |||
537 | /// variant instantiations will have distinct types while others will not. | |||
538 | /// Prefer the emplacement constructors. | |||
539 | /// | |||
540 | /// ## Example | |||
541 | /// ```cpp | |||
542 | /// variant<void, int> v{42}; | |||
543 | /// | |||
544 | /// assert(v.index() == 1); | |||
545 | /// | |||
546 | /// assert(get<1>(v) == 42); | |||
547 | /// ``` | |||
548 | /// | |||
549 | /// @param value The value that is used to construct the alternative | |||
550 | template <typename U> | |||
551 | #ifndef DOXYGEN | |||
552 | requires(!std::is_same_v<std::remove_cvref_t<U>, variant<T...>> && | |||
553 | detail::is_uniquely_constructible_v<U, T...>) | |||
554 | explicit(detail::is_uniquely_explicitly_constructible_v<U, T...>) | |||
555 | #else | |||
556 | CONDITIONALLY_EXPLICIT | |||
557 | #endif | |||
558 | // NOLINTNEXTLINE(hicpp-explicit-conversions) | |||
559 | 16 | constexpr variant(U&& value) | ||
560 | 16 | : variant(emplace_construct_t<0>{}, std::forward<U>(value)) { | ||
561 | 16 | } | ||
562 | ||||
563 | /// @brief Forwarding constructor with initializer list | |||
564 | /// | |||
565 | /// @details | |||
566 | /// A new @ref variant is initialized such that an alternative is | |||
567 | /// constructed in place with the provided `std::initializer_list` | |||
568 | /// as the constructor argument. | |||
569 | /// | |||
570 | /// To avoid ambiguity to the reader, this constructor only participates | |||
571 | /// in overload resulotion when there is only one alternative that could | |||
572 | /// possible be constructed from the initializer list. | |||
573 | /// | |||
574 | /// This constructor is `explicit` if the `std::initializer_list` is not | |||
575 | /// implicitly convertible to the target alternative type. | |||
576 | /// | |||
577 | /// This constructor should be avoided in generic code, because some @ref | |||
578 | /// variant instantiations will have distinct types while others will not. | |||
579 | /// Prefer the emplacement constructors. | |||
580 | /// | |||
581 | /// ## Example | |||
582 | /// ```cpp | |||
583 | /// variant<void, std::vector<int>> v({1, 2, 3, 4, 5}); | |||
584 | /// | |||
585 | /// assert(v.index() == 1); | |||
586 | /// | |||
587 | /// assert(get<1>(v).size() == 5); | |||
588 | /// ``` | |||
589 | /// | |||
590 | /// @param init The `std::initializer_list` that is used to construct the | |||
591 | /// alternative | |||
592 | template <typename U> | |||
593 | #ifndef DOXYGEN | |||
594 | requires(detail::is_uniquely_constructible_v<std::initializer_list<U>, T...>) | |||
595 | explicit(detail::is_uniquely_explicitly_constructible_v<std::initializer_list<U>, T...>) | |||
596 | #else | |||
597 | CONDITIONALLY_EXPLICIT | |||
598 | #endif | |||
599 | 1 | constexpr variant(std::initializer_list<U> init) | ||
600 | 1 | : variant(emplace_construct_t<0>{}, init) { | ||
601 | 1 | } | ||
602 | ||||
603 | /// @brief Destructor | |||
604 | /// | |||
605 | /// @details | |||
606 | /// The contained alternative of the @ref variant will is destroyed in | |||
607 | /// place. | |||
608 | /// | |||
609 | /// The destructor is `noexcept` if all alternative types are nothrow | |||
610 | /// destructible. | |||
611 | 452 | constexpr ~variant() | ||
612 | #ifndef DOXYGEN | |||
613 | noexcept((true && ... && detail::traits<T>::is_nothrow_destructible)) = default; | |||
614 | #else | |||
615 | CONDITIONALLY_NOEXCEPT; | |||
616 | #endif | |||
617 | ||||
618 | /// @brief Copy assignment operator | |||
619 | /// | |||
620 | /// @details | |||
621 | /// Copy assignment of a @ref variant can take one of two possible code | |||
622 | /// paths. | |||
623 | /// | |||
624 | /// If the source and destination @ref variant hold the same alternative | |||
625 | /// (same index), the alternative value is copied via copy assignment. | |||
626 | /// | |||
627 | /// Otherwise, if the source and destination hold different alternatives | |||
628 | /// (different indices, but possibly the same type), the alternative of | |||
629 | /// the destination @ref variant is destroyed in place, and the new | |||
630 | /// alternative is copy constructed. | |||
631 | /// | |||
632 | /// All alternatives *must* be both copy assignable and copy constructible | |||
633 | /// for this function to participate in overload resolution. | |||
634 | /// | |||
635 | /// ## Example | |||
636 | /// ```cpp | |||
637 | /// variant<int, bool> v1{std::in_place_index<0>, 42}; | |||
638 | /// | |||
639 | /// variant<int, bool> v2{std::in_place_index<1>, true}; | |||
640 | /// | |||
641 | /// v1 = v2; | |||
642 | /// | |||
643 | /// assert(holds_alternative<bool>(v1)); | |||
644 | /// | |||
645 | /// assert(v1.index() == 1); | |||
646 | /// | |||
647 | /// assert(get<1>(v1) == true); | |||
648 | /// ``` | |||
649 | 6 | constexpr variant& operator=(const variant& rhs) | ||
650 | #ifndef DOXYGEN | |||
651 | requires(true && ... && | |||
652 | (detail::traits<T>::is_copy_assignable && | |||
653 | detail::traits<T>::is_copy_constructible)) | |||
654 | = default; | |||
655 | #else | |||
656 | ; | |||
657 | #endif | |||
658 | ||||
659 | /// @brief Move assignment operator | |||
660 | /// | |||
661 | /// @details | |||
662 | /// Move assignment of a @ref variant can take one of two possible code | |||
663 | /// paths. | |||
664 | /// | |||
665 | /// If the source and destination @ref variant hold the same alternative | |||
666 | /// (same index), the alternative value is moved from the source to the | |||
667 | /// destination via move assignment. | |||
668 | /// | |||
669 | /// Otherwise, if the source and destination hold different alternatives | |||
670 | /// (different indices, but possibly the same type), the alternative of the | |||
671 | /// destination @ref variant is destroyed in place, and the new alternative | |||
672 | /// is move constructed. | |||
673 | /// | |||
674 | /// The source @ref variant will still contain the same alternative, but | |||
675 | /// the value of the alternative depends on the move assignment or move | |||
676 | /// constructor of the alternative's type. In general, moved values are | |||
677 | /// said to be in a valid, but unspecified, state. | |||
678 | /// | |||
679 | /// All alternatives *must* be both move assignable and move constructible | |||
680 | /// for this function to participate in overload resolution. | |||
681 | /// | |||
682 | /// ## Example | |||
683 | /// ```cpp | |||
684 | /// variant<int, bool> v1{std::in_place_index<0>, 42}; | |||
685 | /// | |||
686 | /// variant<int, bool> v2{std::in_place_index<1>, true}; | |||
687 | /// | |||
688 | /// v1 = std::move(v2); | |||
689 | /// | |||
690 | /// assert(holds_alternative<bool>(v1)); | |||
691 | /// | |||
692 | /// assert(v1.index() == 1); | |||
693 | /// | |||
694 | /// assert(get<1>(v1) == true); | |||
695 | /// ``` | |||
696 | 38 | constexpr variant& operator=(variant&& rhs) | ||
697 | #ifndef DOXYGEN | |||
698 | noexcept((true && ... && | |||
699 | (detail::traits<T>::is_nothrow_move_assignable && | |||
700 | detail::traits<T>::is_nothrow_destructible && | |||
701 | detail::traits<T>::is_nothrow_move_constructible))) | |||
702 | requires(true && ... && | |||
703 | (detail::traits<T>::is_move_assignable && | |||
704 | detail::traits<T>::is_move_constructible)) | |||
705 | = default; | |||
706 | #else | |||
707 | ; | |||
708 | #endif | |||
709 | ||||
710 | private: | |||
711 | template <size_t IDX, typename U> | |||
712 | 18 | constexpr void assign_value(U&& value) { | ||
713 | if constexpr (detail::traits<detail::select_t<IDX, T...>>::template is_assignable< | |||
714 | U>) { | |||
715 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3 times.
|
10 | if (index() == IDX) { |
716 | if constexpr (!std::is_void_v<detail::select_t<IDX, T...>>) { | |||
717 | 2 | data_().template get<IDX>() = std::forward<U>(value); | ||
718 | } | |||
719 | } else { | |||
720 | 8 | data_().template emplace<IDX>(std::forward<U>(value)); | ||
721 | } | |||
722 | } else { | |||
723 | 8 | assign_value<IDX + 1>(std::forward<U>(value)); | ||
724 | } | |||
725 | 18 | } | ||
726 | ||||
727 | public: | |||
728 | /// @brief Forwarding assignment operator | |||
729 | /// | |||
730 | /// @details | |||
731 | /// This function assigns a value directly to an alternative. If the @ref | |||
732 | /// variant already contains the target alternative, the value is assigned | |||
733 | /// using the alternative type's assignemnt operator. Otherwise, the target | |||
734 | /// alternative is constructed with the value. | |||
735 | /// | |||
736 | /// To avoid ambiguity to the reader, this function only participates in | |||
737 | /// overload resolution when there is only one alternative that could | |||
738 | /// possibly be assigned from the value. | |||
739 | /// | |||
740 | /// This operator should be avoided in generic code, because some @ref | |||
741 | /// variant instantiations will have distinct types while others will not. | |||
742 | /// | |||
743 | /// ## Example | |||
744 | /// ```cpp | |||
745 | /// variant<void, int> v{}; | |||
746 | /// | |||
747 | /// v = 42; | |||
748 | /// | |||
749 | /// assert(v.index() == 1); | |||
750 | /// | |||
751 | /// assert(get<1>(v) == 42); | |||
752 | /// ``` | |||
753 | /// | |||
754 | /// @param rhs The value to be assigned to the alternative | |||
755 | template <typename U> | |||
756 | #ifndef DOXYGEN | |||
757 | requires(!std::is_same_v<std::remove_cvref_t<U>, variant> && | |||
758 | detail::is_uniquely_assignable_v<U, T...>) | |||
759 | #endif | |||
760 | 5 | constexpr variant& operator=(U&& rhs) { | ||
761 | 5 | assign_value<0>(std::forward<U>(rhs)); | ||
762 | 5 | return *this; | ||
763 | } | |||
764 | ||||
765 | /// @brief Forwarding assignment operator with initializer list | |||
766 | /// | |||
767 | /// @details | |||
768 | /// This function assigns a `std::initializer_list` directoy to an | |||
769 | /// alternative. If the @ref variant already contains the target | |||
770 | /// alternative, the `std::initializer_list` is assigned uting the | |||
771 | /// alternative type's assignment operator. Otherwise, the target | |||
772 | /// alternative is constructed with the `std::initializer_list`. | |||
773 | /// | |||
774 | /// To avoid ambiguity to the reader, this function only participates in | |||
775 | /// overload resolution when there is only one alternative that could | |||
776 | /// possibly be assigned from the `std::initializer_list`. | |||
777 | /// | |||
778 | /// This opreator should be avoided in generic code, because some @ref | |||
779 | /// variant instantiations will have distinct types while others will not. | |||
780 | /// | |||
781 | /// ## Example | |||
782 | /// ```cpp | |||
783 | /// variant<void, std::vector<int>> v{}; | |||
784 | /// | |||
785 | /// v = {1, 2, 3, 4, 5}; | |||
786 | /// | |||
787 | /// assert(v.index() == 1); | |||
788 | /// | |||
789 | /// assert(get<1>(v).size() == 5); | |||
790 | /// ``` | |||
791 | /// | |||
792 | /// @param rhs The `std::initializer_list` to be assigned to the | |||
793 | /// alternative | |||
794 | template <typename U> | |||
795 | #ifndef DOXYGEN | |||
796 | requires(detail::is_uniquely_assignable_v<std::initializer_list<U>, T...>) | |||
797 | #endif | |||
798 | 2 | constexpr variant& operator=(std::initializer_list<U> rhs) { | ||
799 | 2 | assign_value<0>(rhs); | ||
800 | 2 | return *this; | ||
801 | } | |||
802 | ||||
803 | /// @brief Gets the index of the contained alternative | |||
804 | /// | |||
805 | /// @details | |||
806 | /// The set of alternatives of a @ref variant has a zero-based index based | |||
807 | /// on the order in which they are specified in the @ref variant template | |||
808 | /// arguments. | |||
809 | /// | |||
810 | /// This index is the normalized discriminant of the @ref variant. The | |||
811 | /// discriminant may be represented differently internally, depending on | |||
812 | /// the alternative types, so this function normalizes the discriminant by | |||
813 | /// converting it to a zero-based index in order to provide a common | |||
814 | /// interface for all @ref variant instantiations. | |||
815 | /// | |||
816 | /// ## Example | |||
817 | /// ```cpp | |||
818 | /// variant<int, bool, float&, std::string, void> v{ | |||
819 | /// std::in_place_index<3>, "hello"}; | |||
820 | /// | |||
821 | /// assert(v.index() == 3); | |||
822 | /// ``` | |||
823 | /// | |||
824 | /// @return The index of the contained alternative. | |||
825 | 1258 | [[nodiscard]] constexpr size_t index() const noexcept { return data_().index(); } | ||
826 | ||||
827 | /// @brief Constructs a new alternative in place by index | |||
828 | /// | |||
829 | /// @details | |||
830 | /// This function destroys the alternative that the @ref variant contains | |||
831 | /// before the call, and constructs a new alternative with the specified | |||
832 | /// index in place. | |||
833 | /// | |||
834 | /// ## Example | |||
835 | /// ```cpp | |||
836 | /// variant<int, std::string> v; | |||
837 | /// | |||
838 | /// v.emplace<1>(5, 'a'); | |||
839 | /// | |||
840 | /// assert(holds_alternative<std::string>(v)); | |||
841 | /// | |||
842 | /// assert(v.index() == 1); | |||
843 | /// | |||
844 | /// assert(get<1>(v) == "aaaaa"); | |||
845 | /// ``` | |||
846 | /// | |||
847 | /// @param args Constructor arguments forwarded to the new alternative | |||
848 | /// @return A reference to the new alternative, if applicable | |||
849 | template <size_t I, typename... Args> | |||
850 | constexpr | |||
851 | #ifndef DOXYGEN | |||
852 | typename detail::traits<detail::select_t<I, T...>>::reference | |||
853 | #else | |||
854 | REFERENCE | |||
855 | #endif | |||
856 | 110 | emplace(Args&&... args) { | ||
857 | 110 | data_().template emplace<I>(std::forward<Args>(args)...); | ||
858 | 110 | return data_().template get<I>(); | ||
859 | } | |||
860 | ||||
861 | /// @brief Constructs a new alternative in place by index | |||
862 | /// | |||
863 | /// @details | |||
864 | /// This function destroys the alternative that the @ref variant contains | |||
865 | /// before the call, and constructs a new alternative with the specified | |||
866 | /// index in place. | |||
867 | /// | |||
868 | /// ## Example | |||
869 | /// ```cpp | |||
870 | /// variant<int, std::vector<int>> v; | |||
871 | /// | |||
872 | /// v.emplace<1>({1, 2, 3, 4, 5}); | |||
873 | /// | |||
874 | /// assert(holds_alternative<std::vector<int>>(v)); | |||
875 | /// | |||
876 | /// assert(v.index() == 1); | |||
877 | /// | |||
878 | /// assert(get<1>(v).size() == 5); | |||
879 | /// ``` | |||
880 | /// | |||
881 | /// @param ilist Initializer list forward to the new alternative | |||
882 | /// @param args Constructor arguments forwarded to the new alternative | |||
883 | /// @return A reference to the new alternative, if applicable | |||
884 | template <size_t I, typename U, typename... Args> | |||
885 | constexpr | |||
886 | #ifndef DOXYGEN | |||
887 | typename detail::traits<detail::select_t<I, T...>>::reference | |||
888 | #else | |||
889 | REFERENCE | |||
890 | #endif | |||
891 | 1 | emplace(std::initializer_list<U> ilist, Args&&... args) { | ||
892 | 1 | data_().template emplace<I>(ilist, std::forward<Args>(args)...); | ||
893 | 1 | return data_().template get<I>(); | ||
894 | } | |||
895 | ||||
896 | /// @brief Constructs a new alternative in place by type | |||
897 | /// | |||
898 | /// @details | |||
899 | /// This function destroy the alternative that the @ref variant contains | |||
900 | /// before the call, and constructs a new alternative with the specified | |||
901 | /// type in place. | |||
902 | /// | |||
903 | /// This function only participates in overload resolution if the type, | |||
904 | /// `U`, is unique among all the alternative types of the @ref variant. | |||
905 | /// That is, `variant<A, B, A>` cannot use this function to emplace an | |||
906 | /// alternative of type `A`, but it can use this function to emplace an | |||
907 | /// alternative of type `B`. | |||
908 | /// | |||
909 | /// ## Example | |||
910 | /// ```cpp | |||
911 | /// variant<int, std::string> v; | |||
912 | /// | |||
913 | /// v.emplace<std::string>(5, 'a'); | |||
914 | /// | |||
915 | /// assert(holds_alternative<std::string>(v)); | |||
916 | /// | |||
917 | /// assert(v.index() == 1); | |||
918 | /// | |||
919 | /// assert(get<1>(v) == "aaaaa"); | |||
920 | /// ``` | |||
921 | /// | |||
922 | /// @param args Constructor arguments forwarded to the new alternative | |||
923 | /// @return A reference to the new alternative, if applicable | |||
924 | template <typename U, typename... Args> | |||
925 | #ifndef DOXYGEN | |||
926 | requires(detail::is_unique_v<U, T...>) | |||
927 | #endif | |||
928 | constexpr | |||
929 | #ifndef DOXYGEN | |||
930 | typename detail::traits<U>::reference | |||
931 | #else | |||
932 | REFERENCE | |||
933 | #endif | |||
934 | 10 | emplace(Args&&... args) { | ||
935 | 10 | data_().template emplace<detail::index_of_v<U, T...>>(std::forward<Args>(args)...); | ||
936 | 10 | return data_().template get<detail::index_of_v<U, T...>>(); | ||
937 | } | |||
938 | ||||
939 | /// @brief Constructs a new alternative in place by type | |||
940 | /// | |||
941 | /// @details | |||
942 | /// This function destroy the alternative that the @ref variant contains | |||
943 | /// before the call, and constructs a new alternative with the specified | |||
944 | /// type in place. | |||
945 | /// | |||
946 | /// This function only participates in overload resolution if the type, | |||
947 | /// `U`, is unique among all the alternative types of the @ref variant. | |||
948 | /// That is, `variant<A, B, A>` cannot use this function to emplace an | |||
949 | /// alternative of type `A`, but it can use this function to emplace an | |||
950 | /// alternative of type `B`. | |||
951 | /// | |||
952 | /// ## Example | |||
953 | /// ```cpp | |||
954 | /// variant<int, std::vector<int>> v; | |||
955 | /// | |||
956 | /// v.emplace<std::vector<int>>({1, 2, 3, 4, 5}); | |||
957 | /// | |||
958 | /// assert(holds_alternative<std::vector<int>>(v)); | |||
959 | /// | |||
960 | /// assert(v.index() == 1); | |||
961 | /// | |||
962 | /// assert(get<1>(v).size() == 5); | |||
963 | /// ``` | |||
964 | /// | |||
965 | /// @param ilist Initializer list forward to the new alternative | |||
966 | /// @param args Constructor arguments forwarded to the new alternative | |||
967 | /// @return A reference to the new alternative, if applicable | |||
968 | template <typename U, typename V, typename... Args> | |||
969 | #ifndef DOXYGEN | |||
970 | requires(detail::is_unique_v<U, T...>) | |||
971 | #endif | |||
972 | constexpr | |||
973 | #ifndef DOXYGEN | |||
974 | typename detail::traits<U>::reference | |||
975 | #else | |||
976 | REFERENCE | |||
977 | #endif | |||
978 | 1 | emplace(std::initializer_list<V> ilist, Args&&... args) { | ||
979 | 1 | data_().template emplace<detail::index_of_v<U, T...>>(ilist, | ||
980 | std::forward<Args>(args)...); | |||
981 | 1 | return data_().template get<detail::index_of_v<U, T...>>(); | ||
982 | } | |||
983 | ||||
984 | /// @brief Alternative access operator by index | |||
985 | /// | |||
986 | /// @details | |||
987 | /// This function allows accessing alternatives by index using the square | |||
988 | /// bracket operator. Because the index must be a compile time value, | |||
989 | /// instead of passing the index directly, the index is provided as an | |||
990 | /// instance of @ref index_t. | |||
991 | /// | |||
992 | /// This operator is unchecked and does not throw an exception. Passing an | |||
993 | /// index that does not correspond to the currently contained alternative | |||
994 | /// results in undefined behavior. | |||
995 | /// | |||
996 | /// ## Example | |||
997 | /// ```cpp | |||
998 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
999 | /// | |||
1000 | /// assert(v[index<1>] == 42); | |||
1001 | /// | |||
1002 | /// v[index<1>] = 24; | |||
1003 | /// | |||
1004 | /// assert(get<1>(v) == 24); | |||
1005 | /// ``` | |||
1006 | /// | |||
1007 | /// @param index A tag value that communicates a compile time index | |||
1008 | /// @return A reference to the accessed alternative, if applicable | |||
1009 | template <size_t I> | |||
1010 | [[nodiscard]] constexpr | |||
1011 | #ifndef DOXYGEN | |||
1012 | typename detail::traits<detail::select_t<I, T...>>::reference | |||
1013 | #else | |||
1014 | REFERENCE | |||
1015 | #endif | |||
1016 | 248 | operator[]([[maybe_unused]] index_t<I> index) & noexcept { | ||
1017 | 248 | return data_().template get<I>(); | ||
1018 | } | |||
1019 | ||||
1020 | /// @brief Alternative access operator by index | |||
1021 | /// | |||
1022 | /// @details | |||
1023 | /// This function allows accessing alternatives by index using the square | |||
1024 | /// bracket operator. Because the index must be a compile time value, | |||
1025 | /// instead of passing the index directly, the index is provided as an | |||
1026 | /// instance of @ref index_t. | |||
1027 | /// | |||
1028 | /// This operator is unchecked and does not throw an exception. Passing an | |||
1029 | /// index that does not correspond to the currently contained alternative | |||
1030 | /// results in undefined behavior. | |||
1031 | /// | |||
1032 | /// ## Example | |||
1033 | /// ```cpp | |||
1034 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1035 | /// | |||
1036 | /// assert(v[index<1>] == 42); | |||
1037 | /// | |||
1038 | /// v[index<1>] = 24; | |||
1039 | /// | |||
1040 | /// assert(get<1>(v) == 24); | |||
1041 | /// ``` | |||
1042 | /// | |||
1043 | /// @param index A tag value that communicates a compile time index | |||
1044 | /// @return A reference to the accessed alternative, if applicable | |||
1045 | template <size_t I> | |||
1046 | [[nodiscard]] constexpr | |||
1047 | #ifndef DOXYGEN | |||
1048 | typename detail::traits<detail::select_t<I, T...>>::const_reference | |||
1049 | #else | |||
1050 | CONST_REFERENCE | |||
1051 | #endif | |||
1052 | 200 | operator[]([[maybe_unused]] index_t<I> index) const& noexcept { | ||
1053 | 200 | return data_().template get<I>(); | ||
1054 | } | |||
1055 | ||||
1056 | /// @brief Alternative access operator by index | |||
1057 | /// | |||
1058 | /// @details | |||
1059 | /// This function allows accessing alternatives by index using the square | |||
1060 | /// bracket operator. Because the index must be a compile time value, | |||
1061 | /// instead of passing the index directly, the index is provided as an | |||
1062 | /// instance of @ref index_t. | |||
1063 | /// | |||
1064 | /// This operator is unchecked and does not throw an exception. Passing an | |||
1065 | /// index that does not correspond to the currently contained alternative | |||
1066 | /// results in undefined behavior. | |||
1067 | /// | |||
1068 | /// ## Example | |||
1069 | /// ```cpp | |||
1070 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1071 | /// | |||
1072 | /// assert(v[index<1>] == 42); | |||
1073 | /// | |||
1074 | /// v[index<1>] = 24; | |||
1075 | /// | |||
1076 | /// assert(get<1>(v) == 24); | |||
1077 | /// ``` | |||
1078 | /// | |||
1079 | /// @param index A tag value that communicates a compile time index | |||
1080 | /// @return The accessed alternative value, if applicable | |||
1081 | template <size_t I> | |||
1082 | [[nodiscard]] constexpr | |||
1083 | #ifndef DOXYGEN | |||
1084 | typename detail::traits<detail::select_t<I, T...>>::rvalue_reference | |||
1085 | #else | |||
1086 | RVALUE_REFERENCE | |||
1087 | #endif | |||
1088 | 51 | operator[]([[maybe_unused]] index_t<I> index) && { | ||
1089 | 51 | return std::move(data_()).template get<I>(); | ||
1090 | } | |||
1091 | ||||
1092 | /// @brief Alternative access operator by index | |||
1093 | /// | |||
1094 | /// @details | |||
1095 | /// This function allows accessing alternatives by index using the square | |||
1096 | /// bracket operator. Because the index must be a compile time value, | |||
1097 | /// instead of passing the index directly, the index is provided as an | |||
1098 | /// instance of @ref index_t. | |||
1099 | /// | |||
1100 | /// This operator is unchecked and does not throw an exception. Passing an | |||
1101 | /// index that does not correspond to the currently contained alternative | |||
1102 | /// results in undefined behavior. | |||
1103 | /// | |||
1104 | /// ## Example | |||
1105 | /// ```cpp | |||
1106 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1107 | /// | |||
1108 | /// assert(v[index<1>] == 42); | |||
1109 | /// | |||
1110 | /// v[index<1>] = 24; | |||
1111 | /// | |||
1112 | /// assert(get<1>(v) == 24); | |||
1113 | /// ``` | |||
1114 | /// | |||
1115 | /// @param index A tag value that communicates a compile time index | |||
1116 | /// @return The accessed alternative value, if applicable | |||
1117 | template <size_t I> | |||
1118 | [[nodiscard]] constexpr | |||
1119 | #ifndef DOXYGEN | |||
1120 | typename detail::traits<detail::select_t<I, T...>>::const_rvalue_reference | |||
1121 | #else | |||
1122 | CONST_RVALUE_REFERENCE | |||
1123 | #endif | |||
1124 | 10 | operator[]([[maybe_unused]] index_t<I> index) const&& { | ||
1125 | 10 | return std::move(data_()).template get<I>(); | ||
1126 | } | |||
1127 | ||||
1128 | /// @brief Alternative access operator by type | |||
1129 | /// | |||
1130 | /// @details | |||
1131 | /// This function allows accessing alternatives by type using the square | |||
1132 | /// bracket operator. Because the type must be a compile time value, | |||
1133 | /// the type is provided as an instance of @ref type_t. | |||
1134 | /// | |||
1135 | /// This operator is unchecked and does not throw an exception. Passing a | |||
1136 | /// type that does not correspond to the currently contained alternative | |||
1137 | /// results in undefined behavior. | |||
1138 | /// | |||
1139 | /// This function only participates in overload resolution if the type is | |||
1140 | /// unique across all alternative types of the @ref variant. That is, | |||
1141 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1142 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1143 | /// type `B`. | |||
1144 | /// | |||
1145 | /// ## Example | |||
1146 | /// ```cpp | |||
1147 | /// variant<bool, int, void> v{std::in_place_type<int>, 42}; | |||
1148 | /// | |||
1149 | /// assert(v[type<int>] == 42); | |||
1150 | /// | |||
1151 | /// v[type<int>] = 24; | |||
1152 | /// | |||
1153 | /// assert(get<int>(v) == 24); | |||
1154 | /// ``` | |||
1155 | /// | |||
1156 | /// @param index A tag value that communicates a compile time index | |||
1157 | /// @return A reference to the accessed alternative, if applicable | |||
1158 | template <typename U> | |||
1159 | #ifndef DOXYGEN | |||
1160 | requires detail::is_unique_v<U, T...> | |||
1161 | #endif | |||
1162 | [[nodiscard]] constexpr | |||
1163 | #ifndef DOXYGEN | |||
1164 | typename detail::traits<U>::reference | |||
1165 | #else | |||
1166 | REFERENCE | |||
1167 | #endif | |||
1168 | 30 | operator[]([[maybe_unused]] type_t<U> type) & noexcept { | ||
1169 | 30 | return this->operator[](sumty::index<detail::index_of_v<U, T...>>); | ||
1170 | } | |||
1171 | ||||
1172 | /// @brief Alternative access operator by type | |||
1173 | /// | |||
1174 | /// @details | |||
1175 | /// This function allows accessing alternatives by type using the square | |||
1176 | /// bracket operator. Because the type must be a compile time value, | |||
1177 | /// the type is provided as an instance of @ref type_t. | |||
1178 | /// | |||
1179 | /// This operator is unchecked and does not throw an exception. Passing a | |||
1180 | /// type that does not correspond to the currently contained alternative | |||
1181 | /// results in undefined behavior. | |||
1182 | /// | |||
1183 | /// This function only participates in overload resolution if the type is | |||
1184 | /// unique across all alternative types of the @ref variant. That is, | |||
1185 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1186 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1187 | /// type `B`. | |||
1188 | /// | |||
1189 | /// ## Example | |||
1190 | /// ```cpp | |||
1191 | /// variant<bool, int, void> v{std::in_place_type<int>, 42}; | |||
1192 | /// | |||
1193 | /// assert(v[type<int>] == 42); | |||
1194 | /// | |||
1195 | /// v[type<int>] = 24; | |||
1196 | /// | |||
1197 | /// assert(get<int>(v) == 24); | |||
1198 | /// ``` | |||
1199 | /// | |||
1200 | /// @param index A tag value that communicates a compile time index | |||
1201 | /// @return A reference to the accessed alternative, if applicable | |||
1202 | template <typename U> | |||
1203 | #ifndef DOXYGEN | |||
1204 | requires detail::is_unique_v<U, T...> | |||
1205 | #endif | |||
1206 | [[nodiscard]] constexpr | |||
1207 | #ifndef DOXYGEN | |||
1208 | typename detail::traits<U>::const_reference | |||
1209 | #else | |||
1210 | CONST_REFERENCE | |||
1211 | #endif | |||
1212 | 2 | operator[]([[maybe_unused]] type_t<U> type) const& noexcept { | ||
1213 | 2 | return this->operator[](sumty::index<detail::index_of_v<U, T...>>); | ||
1214 | } | |||
1215 | ||||
1216 | /// @brief Alternative access operator by type | |||
1217 | /// | |||
1218 | /// @details | |||
1219 | /// This function allows accessing alternatives by type using the square | |||
1220 | /// bracket operator. Because the type must be a compile time value, | |||
1221 | /// the type is provided as an instance of @ref type_t. | |||
1222 | /// | |||
1223 | /// This operator is unchecked and does not throw an exception. Passing a | |||
1224 | /// type that does not correspond to the currently contained alternative | |||
1225 | /// results in undefined behavior. | |||
1226 | /// | |||
1227 | /// This function only participates in overload resolution if the type is | |||
1228 | /// unique across all alternative types of the @ref variant. That is, | |||
1229 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1230 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1231 | /// type `B`. | |||
1232 | /// | |||
1233 | /// ## Example | |||
1234 | /// ```cpp | |||
1235 | /// variant<bool, int, void> v{std::in_place_type<int>, 42}; | |||
1236 | /// | |||
1237 | /// assert(v[type<int>] == 42); | |||
1238 | /// | |||
1239 | /// v[type<int>] = 24; | |||
1240 | /// | |||
1241 | /// assert(get<int>(v) == 24); | |||
1242 | /// ``` | |||
1243 | /// | |||
1244 | /// @param index A tag value that communicates a compile time index | |||
1245 | /// @return The accessed alternative value, if applicable | |||
1246 | template <typename U> | |||
1247 | #ifndef DOXYGEN | |||
1248 | requires detail::is_unique_v<U, T...> | |||
1249 | #endif | |||
1250 | [[nodiscard]] constexpr | |||
1251 | #ifndef DOXYGEN | |||
1252 | typename detail::traits<U>::rvalue_reference | |||
1253 | #else | |||
1254 | RVALUE_REFERENCE | |||
1255 | #endif | |||
1256 | 1 | operator[]([[maybe_unused]] type_t<U> type) && { | ||
1257 | 1 | return std::move(*this).operator[](sumty::index<detail::index_of_v<U, T...>>); | ||
1258 | } | |||
1259 | ||||
1260 | /// @brief Alternative access operator by type | |||
1261 | /// | |||
1262 | /// @details | |||
1263 | /// This function allows accessing alternatives by type using the square | |||
1264 | /// bracket operator. Because the type must be a compile time value, | |||
1265 | /// the type is provided as an instance of @ref type_t. | |||
1266 | /// | |||
1267 | /// This operator is unchecked and does not throw an exception. Passing a | |||
1268 | /// type that does not correspond to the currently contained alternative | |||
1269 | /// results in undefined behavior. | |||
1270 | /// | |||
1271 | /// This function only participates in overload resolution if the type is | |||
1272 | /// unique across all alternative types of the @ref variant. That is, | |||
1273 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1274 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1275 | /// type `B`. | |||
1276 | /// | |||
1277 | /// ## Example | |||
1278 | /// ```cpp | |||
1279 | /// variant<bool, int, void> v{std::in_place_type<int>, 42}; | |||
1280 | /// | |||
1281 | /// assert(v[type<int>] == 42); | |||
1282 | /// | |||
1283 | /// v[type<int>] = 24; | |||
1284 | /// | |||
1285 | /// assert(get<int>(v) == 24); | |||
1286 | /// ``` | |||
1287 | /// | |||
1288 | /// @param index A tag value that communicates a compile time index | |||
1289 | /// @return The accessed alternative value, if applicable | |||
1290 | template <typename U> | |||
1291 | #ifndef DOXYGEN | |||
1292 | requires detail::is_unique_v<U, T...> | |||
1293 | #endif | |||
1294 | [[nodiscard]] constexpr | |||
1295 | #ifndef DOXYGEN | |||
1296 | typename detail::traits<U>::const_rvalue_reference | |||
1297 | #else | |||
1298 | CONST_RVALUE_REFERENCE | |||
1299 | #endif | |||
1300 | 1 | operator[]([[maybe_unused]] type_t<U> type) const&& { | ||
1301 | 1 | return std::move(*this).operator[](sumty::index<detail::index_of_v<U, T...>>); | ||
1302 | } | |||
1303 | ||||
1304 | /// @brief Gets an alternative by index | |||
1305 | /// | |||
1306 | /// @details | |||
1307 | /// This function allows accessing alternatives by index, which is provided | |||
1308 | /// as a template argument. | |||
1309 | /// | |||
1310 | /// ## Example | |||
1311 | /// ```cpp | |||
1312 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1313 | /// | |||
1314 | /// assert(v.get<1>() == 42); | |||
1315 | /// | |||
1316 | /// v.get<1>() = 24; | |||
1317 | /// | |||
1318 | /// assert(get<int>(v) == 24); | |||
1319 | /// ``` | |||
1320 | /// | |||
1321 | /// @tparam I The index of the alternative to access. | |||
1322 | /// | |||
1323 | /// @return A reference to the accessed alternative, if applicable. | |||
1324 | /// | |||
1325 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1326 | /// the alternative with the corresponding index. | |||
1327 | template <size_t I> | |||
1328 | [[nodiscard]] constexpr | |||
1329 | #ifndef DOXYGEN | |||
1330 | typename detail::traits<detail::select_t<I, T...>>::reference | |||
1331 | #else | |||
1332 | REFERENCE | |||
1333 | #endif | |||
1334 | 138 | get() & { | ||
1335 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 69 times.
|
138 | if (index() != I) { throw bad_variant_access(); } |
1336 | 138 | return data_().template get<I>(); | ||
1337 | } | |||
1338 | ||||
1339 | /// @brief Gets an alternative by index | |||
1340 | /// | |||
1341 | /// @details | |||
1342 | /// This function allows accessing alternatives by index, which is provided | |||
1343 | /// as a template argument. | |||
1344 | /// | |||
1345 | /// ## Example | |||
1346 | /// ```cpp | |||
1347 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1348 | /// | |||
1349 | /// assert(v.get<1>() == 42); | |||
1350 | /// | |||
1351 | /// v.get<1>() = 24; | |||
1352 | /// | |||
1353 | /// assert(get<int>(v) == 24); | |||
1354 | /// ``` | |||
1355 | /// | |||
1356 | /// @tparam I The index of the alternative to access. | |||
1357 | /// | |||
1358 | /// @return A reference to the accessed alternative, if applicable. | |||
1359 | /// | |||
1360 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1361 | /// the alternative with the corresponding index. | |||
1362 | template <size_t I> | |||
1363 | [[nodiscard]] constexpr | |||
1364 | #ifndef DOXYGEN | |||
1365 | typename detail::traits<detail::select_t<I, T...>>::const_reference | |||
1366 | #else | |||
1367 | CONST_REFERENCE | |||
1368 | #endif | |||
1369 | 10 | get() const& { | ||
1370 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 6 times.
|
10 | if (index() != I) { throw bad_variant_access(); } |
1371 | 10 | return data_().template get<I>(); | ||
1372 | } | |||
1373 | ||||
1374 | /// @brief Gets an alternative by index | |||
1375 | /// | |||
1376 | /// @details | |||
1377 | /// This function allows accessing alternatives by index, which is provided | |||
1378 | /// as a template argument. | |||
1379 | /// | |||
1380 | /// ## Example | |||
1381 | /// ```cpp | |||
1382 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1383 | /// | |||
1384 | /// assert(v.get<1>() == 42); | |||
1385 | /// | |||
1386 | /// v.get<1>() = 24; | |||
1387 | /// | |||
1388 | /// assert(get<int>(v) == 24); | |||
1389 | /// ``` | |||
1390 | /// | |||
1391 | /// @tparam I The index of the alternative to access. | |||
1392 | /// | |||
1393 | /// @return The accessed alternative value, if applicable. | |||
1394 | /// | |||
1395 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1396 | /// the alternative with the corresponding index. | |||
1397 | template <size_t I> | |||
1398 | [[nodiscard]] constexpr | |||
1399 | #ifndef DOXYGEN | |||
1400 | typename detail::traits<detail::select_t<I, T...>>::rvalue_reference | |||
1401 | #else | |||
1402 | RVALUE_REFERENCE | |||
1403 | #endif | |||
1404 | 2 | get() && { | ||
1405 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (index() != I) { throw bad_variant_access(); } |
1406 | 2 | return std::move(data_()).template get<I>(); | ||
1407 | } | |||
1408 | ||||
1409 | /// @brief Gets an alternative by index | |||
1410 | /// | |||
1411 | /// @details | |||
1412 | /// This function allows accessing alternatives by index, which is provided | |||
1413 | /// as a template argument. | |||
1414 | /// | |||
1415 | /// ## Example | |||
1416 | /// ```cpp | |||
1417 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1418 | /// | |||
1419 | /// assert(v.get<1>() == 42); | |||
1420 | /// | |||
1421 | /// v.get<1>() = 24; | |||
1422 | /// | |||
1423 | /// assert(get<int>(v) == 24); | |||
1424 | /// ``` | |||
1425 | /// | |||
1426 | /// @tparam I The index of the alternative to access. | |||
1427 | /// | |||
1428 | /// @return The accessed alternative value, if applicable. | |||
1429 | /// | |||
1430 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1431 | /// the alternative with the corresponding index. | |||
1432 | template <size_t I> | |||
1433 | [[nodiscard]] constexpr | |||
1434 | #ifndef DOXYGEN | |||
1435 | typename detail::traits<detail::select_t<I, T...>>::const_rvalue_reference | |||
1436 | #else | |||
1437 | CONST_RVALUE_REFERENCE | |||
1438 | #endif | |||
1439 | 2 | get() const&& { | ||
1440 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (index() != I) { throw bad_variant_access(); } |
1441 | 2 | return std::move(data_()).template get<I>(); | ||
1442 | } | |||
1443 | ||||
1444 | /// @brief Gets an alternative by type | |||
1445 | /// | |||
1446 | /// @details | |||
1447 | /// This function allows accessing alternatives by type, which is provided | |||
1448 | /// as a template argument. | |||
1449 | /// | |||
1450 | /// This function only participates in overload resolution if the type is | |||
1451 | /// unique across all alternative types of the @ref variant. That is, | |||
1452 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1453 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1454 | /// type `B`. | |||
1455 | /// | |||
1456 | /// ## Example | |||
1457 | /// ```cpp | |||
1458 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1459 | /// | |||
1460 | /// assert(v.get<int>() == 42); | |||
1461 | /// | |||
1462 | /// v.get<int>() = 24; | |||
1463 | /// | |||
1464 | /// assert(get<int>(v) == 24); | |||
1465 | /// ``` | |||
1466 | /// | |||
1467 | /// @tparam U The type of the alternative to access. | |||
1468 | /// | |||
1469 | /// @return A reference to the accessed alternative, if applicable. | |||
1470 | /// | |||
1471 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1472 | /// the alternative with the corresponding type. | |||
1473 | template <typename U> | |||
1474 | #ifndef DOXYGEN | |||
1475 | requires detail::is_unique_v<U, T...> | |||
1476 | #endif | |||
1477 | [[nodiscard]] constexpr | |||
1478 | #ifndef DOXYGEN | |||
1479 | typename detail::traits<U>::reference | |||
1480 | #else | |||
1481 | REFERENCE | |||
1482 | #endif | |||
1483 | 24 | get() & { | ||
1484 | 24 | return this->template get<detail::index_of_v<U, T...>>(); | ||
1485 | } | |||
1486 | ||||
1487 | /// @brief Gets an alternative by type | |||
1488 | /// | |||
1489 | /// @details | |||
1490 | /// This function allows accessing alternatives by type, which is provided | |||
1491 | /// as a template argument. | |||
1492 | /// | |||
1493 | /// This function only participates in overload resolution if the type is | |||
1494 | /// unique across all alternative types of the @ref variant. That is, | |||
1495 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1496 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1497 | /// type `B`. | |||
1498 | /// | |||
1499 | /// ## Example | |||
1500 | /// ```cpp | |||
1501 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1502 | /// | |||
1503 | /// assert(v.get<int>() == 42); | |||
1504 | /// | |||
1505 | /// v.get<int>() = 24; | |||
1506 | /// | |||
1507 | /// assert(get<int>(v) == 24); | |||
1508 | /// ``` | |||
1509 | /// | |||
1510 | /// @tparam U The type of the alternative to access. | |||
1511 | /// | |||
1512 | /// @return A reference to the accessed alternative, if applicable. | |||
1513 | /// | |||
1514 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1515 | /// the alternative with the corresponding type. | |||
1516 | template <typename U> | |||
1517 | #ifndef DOXYGEN | |||
1518 | requires detail::is_unique_v<U, T...> | |||
1519 | #endif | |||
1520 | [[nodiscard]] constexpr | |||
1521 | #ifndef DOXYGEN | |||
1522 | typename detail::traits<U>::const_reference | |||
1523 | #else | |||
1524 | CONST_REFERENCE | |||
1525 | #endif | |||
1526 | 1 | get() const& { | ||
1527 | 1 | return this->template get<detail::index_of_v<U, T...>>(); | ||
1528 | } | |||
1529 | ||||
1530 | /// @brief Gets an alternative by type | |||
1531 | /// | |||
1532 | /// @details | |||
1533 | /// This function allows accessing alternatives by type, which is provided | |||
1534 | /// as a template argument. | |||
1535 | /// | |||
1536 | /// This function only participates in overload resolution if the type is | |||
1537 | /// unique across all alternative types of the @ref variant. That is, | |||
1538 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1539 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1540 | /// type `B`. | |||
1541 | /// | |||
1542 | /// ## Example | |||
1543 | /// ```cpp | |||
1544 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1545 | /// | |||
1546 | /// assert(v.get<int>() == 42); | |||
1547 | /// | |||
1548 | /// v.get<int>() = 24; | |||
1549 | /// | |||
1550 | /// assert(get<int>(v) == 24); | |||
1551 | /// ``` | |||
1552 | /// | |||
1553 | /// @tparam U The type of the alternative to access. | |||
1554 | /// | |||
1555 | /// @return The accessed alternative value, if applicable. | |||
1556 | /// | |||
1557 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1558 | /// the alternative with the corresponding type. | |||
1559 | template <typename U> | |||
1560 | #ifndef DOXYGEN | |||
1561 | requires detail::is_unique_v<U, T...> | |||
1562 | #endif | |||
1563 | [[nodiscard]] constexpr | |||
1564 | #ifndef DOXYGEN | |||
1565 | typename detail::traits<U>::rvalue_reference | |||
1566 | #else | |||
1567 | RVALUE_REFERENCE | |||
1568 | #endif | |||
1569 | 1 | get() && { | ||
1570 | 1 | return std::move(*this).template get<detail::index_of_v<U, T...>>(); | ||
1571 | } | |||
1572 | ||||
1573 | /// @brief Gets an alternative by type | |||
1574 | /// | |||
1575 | /// @details | |||
1576 | /// This function allows accessing alternatives by type, which is | |||
1577 | /// provided as a template argument. | |||
1578 | /// | |||
1579 | /// This function only participates in overload resolution if the type is | |||
1580 | /// unique across all alternative types of the @ref variant. That is, | |||
1581 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1582 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1583 | /// type `B`. | |||
1584 | /// | |||
1585 | /// ## Example | |||
1586 | /// ```cpp | |||
1587 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1588 | /// | |||
1589 | /// assert(v.get<int>() == 42); | |||
1590 | /// | |||
1591 | /// v.get<int>() = 24; | |||
1592 | /// | |||
1593 | /// assert(get<int>(v) == 24); | |||
1594 | /// ``` | |||
1595 | /// | |||
1596 | /// @tparam U The type of the alternative to access. | |||
1597 | /// | |||
1598 | /// @return The accessed alternative value, if applicable. | |||
1599 | /// | |||
1600 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
1601 | /// the alternative with the corresponding type. | |||
1602 | template <typename U> | |||
1603 | #ifndef DOXYGEN | |||
1604 | requires detail::is_unique_v<U, T...> | |||
1605 | #endif | |||
1606 | [[nodiscard]] constexpr | |||
1607 | #ifndef DOXYGEN | |||
1608 | typename detail::traits<U>::const_rvalue_reference | |||
1609 | #else | |||
1610 | CONST_RVALUE_REFERENCE | |||
1611 | #endif | |||
1612 | 1 | get() const&& { | ||
1613 | 1 | return std::move(*this).template get<detail::index_of_v<U, T...>>(); | ||
1614 | } | |||
1615 | ||||
1616 | /// @brief Gets an alternative pointer by index if the @ref variant holds it | |||
1617 | /// | |||
1618 | /// @details | |||
1619 | /// This functions tries to access an alternative by index. If the @ref | |||
1620 | /// variant contains the alternative, this function returns a pointer to | |||
1621 | /// the alternative, if applicable. If the @ref variant does not contain | |||
1622 | /// the alternative, this function returns null. In the case where the | |||
1623 | /// alternative is of type `void`, this function does nothing. | |||
1624 | /// | |||
1625 | /// ## Example | |||
1626 | /// ```cpp | |||
1627 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1628 | /// | |||
1629 | /// assert(*v.get_if<1>() == 42); | |||
1630 | /// | |||
1631 | /// *v.get_if<1>() = 24; | |||
1632 | /// | |||
1633 | /// assert(*v.get_if<1>() == 24); | |||
1634 | /// | |||
1635 | /// assert(v.get_if<0>() == nullptr); | |||
1636 | /// ``` | |||
1637 | /// | |||
1638 | /// @tparam I The index of the alternative to access. | |||
1639 | /// | |||
1640 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
1641 | template <size_t I> | |||
1642 | [[nodiscard]] constexpr | |||
1643 | #ifndef DOXYGEN | |||
1644 | typename detail::traits<detail::select_t<I, T...>>::pointer | |||
1645 | #else | |||
1646 | POINTER | |||
1647 | #endif | |||
1648 | 52 | get_if() noexcept { | ||
1649 | using ptr_t = typename detail::traits<detail::select_t<I, T...>>::pointer; | |||
1650 | if constexpr (!std::is_void_v<ptr_t>) { | |||
1651 | ptr_t ret; | |||
1652 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 18 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 18 times.
|
52 | if (index() == I) { |
1653 | 16 | ret = &data_().template get<I>(); | ||
1654 | } else { | |||
1655 | 36 | ret = nullptr; | ||
1656 | } | |||
1657 | 52 | return ret; | ||
1658 | } else { | |||
1659 | return; | |||
1660 | } | |||
1661 | } | |||
1662 | ||||
1663 | /// @brief Gets an alternative pointer by index if the @ref variant holds it | |||
1664 | /// | |||
1665 | /// @details | |||
1666 | /// This functions tries to access an alternative by index. If the @ref | |||
1667 | /// variant contains the alternative, this function returns a pointer to | |||
1668 | /// the alternative, if applicable. If the @ref variant does not contain | |||
1669 | /// the alternative, this function returns null. In the case where the | |||
1670 | /// alternative is of type `void`, this function does nothing. | |||
1671 | /// | |||
1672 | /// ## Example | |||
1673 | /// ```cpp | |||
1674 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1675 | /// | |||
1676 | /// assert(*v.get_if<1>() == 42); | |||
1677 | /// | |||
1678 | /// *v.get_if<1>() = 24; | |||
1679 | /// | |||
1680 | /// assert(*v.get_if<1>() == 24); | |||
1681 | /// | |||
1682 | /// assert(v.get_if<0>() == nullptr); | |||
1683 | /// ``` | |||
1684 | /// | |||
1685 | /// @tparam I The index of the alternative to access. | |||
1686 | /// | |||
1687 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
1688 | template <size_t I> | |||
1689 | [[nodiscard]] constexpr | |||
1690 | #ifndef DOXYGEN | |||
1691 | typename detail::traits<detail::select_t<I, T...>>::const_pointer | |||
1692 | #else | |||
1693 | CONST_POINTER | |||
1694 | #endif | |||
1695 | 16 | get_if() const noexcept { | ||
1696 | using ptr_t = typename detail::traits<detail::select_t<I, T...>>::const_pointer; | |||
1697 | if constexpr (!std::is_void_v<ptr_t>) { | |||
1698 | ptr_t ret; | |||
1699 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 4 times.
|
16 | if (index() == I) { |
1700 | 8 | ret = &data_().template get<I>(); | ||
1701 | } else { | |||
1702 | 8 | ret = nullptr; | ||
1703 | } | |||
1704 | 16 | return ret; | ||
1705 | } else { | |||
1706 | return; | |||
1707 | } | |||
1708 | } | |||
1709 | ||||
1710 | /// @brief Gets an alternative pointer by type if the @ref variant holds it | |||
1711 | /// | |||
1712 | /// @details | |||
1713 | /// This functions tries to access an alternative by type. If the @ref | |||
1714 | /// variant contains the alternative, this function returns a pointer to | |||
1715 | /// the alternative, if applicable. If the @ref variant does not contain | |||
1716 | /// the alternative, this function returns null. In the case where the | |||
1717 | /// alternative is of type `void`, this function does nothing. | |||
1718 | /// | |||
1719 | /// This function only participates in overload resolution if the type is | |||
1720 | /// unique across all alternative types of the @ref variant. That is, | |||
1721 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1722 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1723 | /// type `B`. | |||
1724 | /// | |||
1725 | /// ## Example | |||
1726 | /// ```cpp | |||
1727 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1728 | /// | |||
1729 | /// assert(*v.get_if<int>() == 42); | |||
1730 | /// | |||
1731 | /// *v.get_if<int>() = 24; | |||
1732 | /// | |||
1733 | /// assert(*v.get_if<int>() == 24); | |||
1734 | /// | |||
1735 | /// assert(v.get_if<bool>() == nullptr); | |||
1736 | /// ``` | |||
1737 | /// | |||
1738 | /// @tparam I The index of the alternative to access. | |||
1739 | /// | |||
1740 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
1741 | template <typename U> | |||
1742 | #ifndef DOXYGEN | |||
1743 | requires detail::is_unique_v<U, T...> | |||
1744 | #endif | |||
1745 | [[nodiscard]] constexpr | |||
1746 | #ifndef DOXYGEN | |||
1747 | typename detail::traits<U>::pointer | |||
1748 | #else | |||
1749 | POINTER | |||
1750 | #endif | |||
1751 | 26 | get_if() noexcept { | ||
1752 | 26 | return get_if<detail::index_of_v<U, T...>>(); | ||
1753 | } | |||
1754 | ||||
1755 | /// @brief Gets an alternative pointer by type if the @ref variant holds it | |||
1756 | /// | |||
1757 | /// @details | |||
1758 | /// This functions tries to access an alternative by type. If the @ref | |||
1759 | /// variant contains the alternative, this function returns a pointer to | |||
1760 | /// the alternative, if applicable. If the @ref variant does not contain | |||
1761 | /// the alternative, this function returns null. In the case where the | |||
1762 | /// alternative is of type `void`, this function does nothing. | |||
1763 | /// | |||
1764 | /// This function only participates in overload resolution if the type is | |||
1765 | /// unique across all alternative types of the @ref variant. That is, | |||
1766 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
1767 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
1768 | /// type `B`. | |||
1769 | /// | |||
1770 | /// ## Example | |||
1771 | /// ```cpp | |||
1772 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
1773 | /// | |||
1774 | /// assert(*v.get_if<int>() == 42); | |||
1775 | /// | |||
1776 | /// *v.get_if<int>() = 24; | |||
1777 | /// | |||
1778 | /// assert(*v.get_if<int>() == 24); | |||
1779 | /// | |||
1780 | /// assert(v.get_if<bool>() == nullptr); | |||
1781 | /// ``` | |||
1782 | /// | |||
1783 | /// @tparam I The index of the alternative to access. | |||
1784 | /// | |||
1785 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
1786 | template <typename U> | |||
1787 | #ifndef DOXYGEN | |||
1788 | requires detail::is_unique_v<U, T...> | |||
1789 | #endif | |||
1790 | [[nodiscard]] constexpr | |||
1791 | #ifndef DOXYGEN | |||
1792 | typename detail::traits<U>::const_pointer | |||
1793 | #else | |||
1794 | CONST_POINTER | |||
1795 | #endif | |||
1796 | 8 | get_if() const noexcept { | ||
1797 | 8 | return get_if<detail::index_of_v<U, T...>>(); | ||
1798 | } | |||
1799 | ||||
1800 | /// @brief Checks if a @ref variant contains a particular alternative. | |||
1801 | /// | |||
1802 | /// @details | |||
1803 | /// Given a type parameter, this function checks if the @ref variant currently | |||
1804 | /// holds an alternative that has the exact same type. | |||
1805 | /// | |||
1806 | /// ## Example | |||
1807 | /// ```cpp | |||
1808 | /// variant<int, bool, int> v1{std::in_place_index<0>, 42}; | |||
1809 | /// | |||
1810 | /// assert(v1.holds_alternative<int>()); | |||
1811 | /// | |||
1812 | /// variant<int, bool, int> v2{std::in_place_index<2>, 42}; | |||
1813 | /// | |||
1814 | /// assert(v2.holds_alternative<int>()); | |||
1815 | /// ``` | |||
1816 | /// | |||
1817 | /// @return `true` if the @ref variant holds an alternative of the given type. | |||
1818 | template <typename U> | |||
1819 | 118 | [[nodiscard]] constexpr bool holds_alternative() const noexcept { | ||
1820 | if constexpr (detail::is_unique_v<U, T...>) { | |||
1821 | 112 | return index() == detail::index_of_v<U, T...>; | ||
1822 | } else { | |||
1823 | 6 | return holds_alt_impl<0, U>(); | ||
1824 | } | |||
1825 | } | |||
1826 | ||||
1827 | /// @brief Calls a visitor callable with the contained alternative | |||
1828 | /// | |||
1829 | /// @details | |||
1830 | /// This function calls the visitor as `std::invoke(visitor, alternative)` | |||
1831 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
1832 | /// be able to accecpt any alternative type as an argument. In the case of | |||
1833 | /// an alternative of type `void`, the visitor must be callable as | |||
1834 | /// `std::invoke(visitor, void_v)`. | |||
1835 | /// | |||
1836 | /// Note that the @ref overload function can be helpful for defining a | |||
1837 | /// visitor inline. | |||
1838 | /// | |||
1839 | /// Also note that this function is implemented as a compile-time-defined | |||
1840 | /// jump table (array of function pointers). In performance critical | |||
1841 | /// applications, be wary of any assumptions about how well or poorly your | |||
1842 | /// compiler will optimize a call to this function. | |||
1843 | /// | |||
1844 | /// ## Example | |||
1845 | /// ```cpp | |||
1846 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
1847 | /// | |||
1848 | /// v1.visit(overload( | |||
1849 | /// [](bool bool_value) { assert(false); }, | |||
1850 | /// [](int int_value) { assert(int_value == 42); }, | |||
1851 | /// [](void_t void_value) { assert(false); } | |||
1852 | /// )); | |||
1853 | /// ``` | |||
1854 | /// | |||
1855 | /// @param visitor The callable object that will be passed an alternative. | |||
1856 | /// @return The return value of the visitor, if any. | |||
1857 | template <typename V> | |||
1858 | constexpr | |||
1859 | #ifndef DOXYGEN | |||
1860 | detail::invoke_result_t< | |||
1861 | V&&, | |||
1862 | typename detail::traits<detail::select_t<0, T...>>::reference> | |||
1863 | #else | |||
1864 | DEDUCED | |||
1865 | #endif | |||
1866 | 36 | visit(V&& visitor) & { | ||
1867 | 36 | return detail::visit_impl<V, variant&, T...>(std::forward<V>(visitor), *this); | ||
1868 | } | |||
1869 | ||||
1870 | /// @brief Calls a visitor callable with the contained alternative | |||
1871 | /// | |||
1872 | /// @details | |||
1873 | /// This function calls the visitor as `std::invoke(visitor, alternative)` | |||
1874 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
1875 | /// be able to accecpt any alternative type as an argument. In the case of | |||
1876 | /// an alternative of type `void`, the visitor must be callable as | |||
1877 | /// `std::invoke(visitor, void_v)`. | |||
1878 | /// | |||
1879 | /// Note that the @ref overload function can be helpful for defining a | |||
1880 | /// visitor inline. | |||
1881 | /// | |||
1882 | /// Also note that this function is implemented as a compile-time-defined | |||
1883 | /// jump table (array of function pointers). In performance critical | |||
1884 | /// applications, be wary of any assumptions about how well or poorly your | |||
1885 | /// compiler will optimize a call to this function. | |||
1886 | /// | |||
1887 | /// ## Example | |||
1888 | /// ```cpp | |||
1889 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
1890 | /// | |||
1891 | /// v1.visit(overload( | |||
1892 | /// [](bool bool_value) { assert(false); }, | |||
1893 | /// [](int int_value) { assert(int_value == 42); }, | |||
1894 | /// [](void_t void_value) { assert(false); } | |||
1895 | /// )); | |||
1896 | /// ``` | |||
1897 | /// | |||
1898 | /// @param visitor The callable object that will be passed an alternative. | |||
1899 | /// @return The return value of the visitor, if any. | |||
1900 | template <typename V> | |||
1901 | constexpr | |||
1902 | #ifndef DOXYGEN | |||
1903 | detail::invoke_result_t< | |||
1904 | V&&, | |||
1905 | typename detail::traits<detail::select_t<0, T...>>::const_reference> | |||
1906 | #else | |||
1907 | DEDUCED | |||
1908 | #endif | |||
1909 | 8 | visit(V&& visitor) const& { | ||
1910 | 8 | return detail::visit_impl<V, const variant&, T...>(std::forward<V>(visitor), *this); | ||
1911 | } | |||
1912 | ||||
1913 | /// @brief Calls a visitor callable with the contained alternative | |||
1914 | /// | |||
1915 | /// @details | |||
1916 | /// This function calls the visitor as `std::invoke(visitor, alternative)` | |||
1917 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
1918 | /// be able to accecpt any alternative type as an argument. In the case of | |||
1919 | /// an alternative of type `void`, the visitor must be callable as | |||
1920 | /// `std::invoke(visitor, void_v)`. | |||
1921 | /// | |||
1922 | /// Note that the @ref overload function can be helpful for defining a | |||
1923 | /// visitor inline. | |||
1924 | /// | |||
1925 | /// Also note that this function is implemented as a compile-time-defined | |||
1926 | /// jump table (array of function pointers). In performance critical | |||
1927 | /// applications, be wary of any assumptions about how well or poorly your | |||
1928 | /// compiler will optimize a call to this function. | |||
1929 | /// | |||
1930 | /// ## Example | |||
1931 | /// ```cpp | |||
1932 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
1933 | /// | |||
1934 | /// v1.visit(overload( | |||
1935 | /// [](bool bool_value) { assert(false); }, | |||
1936 | /// [](int int_value) { assert(int_value == 42); }, | |||
1937 | /// [](void_t void_value) { assert(false); } | |||
1938 | /// )); | |||
1939 | /// ``` | |||
1940 | /// | |||
1941 | /// @param visitor The callable object that will be passed an alternative. | |||
1942 | /// @return The return value of the visitor, if any. | |||
1943 | template <typename V> | |||
1944 | constexpr | |||
1945 | #ifndef DOXYGEN | |||
1946 | detail::invoke_result_t< | |||
1947 | V&&, | |||
1948 | typename detail::traits<detail::select_t<0, T...>>::rvalue_reference> | |||
1949 | #else | |||
1950 | DEDUCED | |||
1951 | #endif | |||
1952 | 4 | visit(V&& visitor) && { | ||
1953 | 4 | return detail::visit_impl<V, variant&&, T...>(std::forward<V>(visitor), | ||
1954 | 8 | std::move(*this)); | ||
1955 | } | |||
1956 | ||||
1957 | /// @brief Calls a visitor callable with the contained alternative | |||
1958 | /// | |||
1959 | /// @details | |||
1960 | /// This function calls the visitor as `std::invoke(visitor, alternative)` | |||
1961 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
1962 | /// be able to accecpt any alternative type as an argument. In the case of | |||
1963 | /// an alternative of type `void`, the visitor must be callable as | |||
1964 | /// `std::invoke(visitor, void_v)`. | |||
1965 | /// | |||
1966 | /// Note that the @ref overload function can be helpful for defining a | |||
1967 | /// visitor inline. | |||
1968 | /// | |||
1969 | /// Also note that this function is implemented as a compile-time-defined | |||
1970 | /// jump table (array of function pointers). In performance critical | |||
1971 | /// applications, be wary of any assumptions about how well or poorly your | |||
1972 | /// compiler will optimize a call to this function. | |||
1973 | /// | |||
1974 | /// ## Example | |||
1975 | /// ```cpp | |||
1976 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
1977 | /// | |||
1978 | /// v1.visit(overload( | |||
1979 | /// [](bool bool_value) { assert(false); }, | |||
1980 | /// [](int int_value) { assert(int_value == 42); }, | |||
1981 | /// [](void_t void_value) { assert(false); } | |||
1982 | /// )); | |||
1983 | /// ``` | |||
1984 | /// | |||
1985 | /// @param visitor The callable object that will be passed an alternative. | |||
1986 | /// @return The return value of the visitor, if any. | |||
1987 | template <typename V> | |||
1988 | constexpr | |||
1989 | #ifndef DOXYGEN | |||
1990 | detail::invoke_result_t< | |||
1991 | V&&, | |||
1992 | typename detail::traits<detail::select_t<0, T...>>::const_rvalue_reference> | |||
1993 | #else | |||
1994 | DEDUCED | |||
1995 | #endif | |||
1996 | 4 | visit(V&& visitor) const&& { | ||
1997 | 4 | return detail::visit_impl<V, const variant&&, T...>(std::forward<V>(visitor), | ||
1998 | 8 | std::move(*this)); | ||
1999 | } | |||
2000 | ||||
2001 | /// @brief Calls a visitor callable with the contained alternative and metadata | |||
2002 | /// | |||
2003 | /// @details | |||
2004 | /// This function calls the visitor as `std::invoke(visitor, alternative, info)`, | |||
2005 | /// and returns the result of that call, if any. As such, `visitor` *must* be | |||
2006 | /// able to accept any alternative type as an argument. In the case of an | |||
2007 | /// alternative of type `void`, the visitor must be callable as | |||
2008 | /// `std::invoke(visitor, void_v, info)`. | |||
2009 | /// | |||
2010 | /// The `info` argument passed to the visitor, which differentiates this | |||
2011 | /// function from `.visit(...)`, communicates `constexpr` information about | |||
2012 | /// the alternative being visited. The type of the `info` object is not | |||
2013 | /// meant to be named, but it has the API shown below. Note that `info` is | |||
2014 | /// always an empty type. | |||
2015 | /// | |||
2016 | /// ``` | |||
2017 | /// struct alternative_info { | |||
2018 | /// // index of the alternative in the source variant | |||
2019 | /// static inline constexpr size_t index = ...; | |||
2020 | /// | |||
2021 | /// // type of the alternative as declared in the source variant | |||
2022 | /// using type = ...; | |||
2023 | /// }; | |||
2024 | /// ``` | |||
2025 | /// | |||
2026 | /// Note that the @ref overload function can be helpful for defining a | |||
2027 | /// visitor inline. | |||
2028 | /// | |||
2029 | /// Also note that this function is implemented as a compile-time-defined | |||
2030 | /// jump table (array of function pointers). In performance critical | |||
2031 | /// applications, be wary of any assumptions about how well or poorly your | |||
2032 | /// compiler will optimize a call to this function. | |||
2033 | /// | |||
2034 | /// ## Example | |||
2035 | /// ``` | |||
2036 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2037 | /// | |||
2038 | /// v1.visit_informed([](auto value, auto info) { | |||
2039 | /// if constexpr (info.index == 0) { | |||
2040 | /// assert(false); | |||
2041 | /// } else if constexpr (info.index == 1) { | |||
2042 | /// assert(value == 42); | |||
2043 | /// } else if constexpr (info.index == 2) { | |||
2044 | /// assert(false); | |||
2045 | /// } | |||
2046 | /// }); | |||
2047 | /// ``` | |||
2048 | /// | |||
2049 | /// @param visitor The callable object that will be passed an alternative. | |||
2050 | /// @return The return value of the visitor, if any. | |||
2051 | template <typename V> | |||
2052 | constexpr | |||
2053 | #ifndef DOXYGEN | |||
2054 | detail::invoke_result_t< | |||
2055 | V&&, | |||
2056 | typename detail::traits<detail::select_t<0, T...>>::reference, | |||
2057 | detail::alternative_info<0, variant>> | |||
2058 | #else | |||
2059 | DEDUCED | |||
2060 | #endif | |||
2061 | 1 | visit_informed(V&& visitor) & { | ||
2062 | 1 | return detail::visit_informed_impl<V, variant&, T...>(std::forward<V>(visitor), | ||
2063 | 1 | *this); | ||
2064 | } | |||
2065 | ||||
2066 | /// @brief Calls a visitor callable with the contained alternative and metadata | |||
2067 | /// | |||
2068 | /// @details | |||
2069 | /// This function calls the visitor as `std::invoke(visitor, alternative, info)`, | |||
2070 | /// and returns the result of that call, if any. As such, `visitor` *must* be | |||
2071 | /// able to accept any alternative type as an argument. In the case of an | |||
2072 | /// alternative of type `void`, the visitor must be callable as | |||
2073 | /// `std::invoke(visitor, void_v, info)`. | |||
2074 | /// | |||
2075 | /// The `info` argument passed to the visitor, which differentiates this | |||
2076 | /// function from `.visit(...)`, communicates `constexpr` information about | |||
2077 | /// the alternative being visited. The type of the `info` object is not | |||
2078 | /// meant to be named, but it has the API shown below. Note that `info` is | |||
2079 | /// always an empty type. | |||
2080 | /// | |||
2081 | /// ``` | |||
2082 | /// struct alternative_info { | |||
2083 | /// // index of the alternative in the source variant | |||
2084 | /// static inline constexpr size_t index = ...; | |||
2085 | /// | |||
2086 | /// // type of the alternative as declared in the source variant | |||
2087 | /// using type = ...; | |||
2088 | /// }; | |||
2089 | /// ``` | |||
2090 | /// | |||
2091 | /// Note that the @ref overload function can be helpful for defining a | |||
2092 | /// visitor inline. | |||
2093 | /// | |||
2094 | /// Also note that this function is implemented as a compile-time-defined | |||
2095 | /// jump table (array of function pointers). In performance critical | |||
2096 | /// applications, be wary of any assumptions about how well or poorly your | |||
2097 | /// compiler will optimize a call to this function. | |||
2098 | /// | |||
2099 | /// ## Example | |||
2100 | /// ``` | |||
2101 | /// const variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2102 | /// | |||
2103 | /// v1.visit_informed([](auto value, auto info) { | |||
2104 | /// if constexpr (info.index == 0) { | |||
2105 | /// assert(false); | |||
2106 | /// } else if constexpr (info.index == 1) { | |||
2107 | /// assert(value == 42); | |||
2108 | /// } else if constexpr (info.index == 2) { | |||
2109 | /// assert(false); | |||
2110 | /// } | |||
2111 | /// }); | |||
2112 | /// ``` | |||
2113 | /// | |||
2114 | /// @param visitor The callable object that will be passed an alternative. | |||
2115 | /// @return The return value of the visitor, if any. | |||
2116 | template <typename V> | |||
2117 | constexpr | |||
2118 | #ifndef DOXYGEN | |||
2119 | detail::invoke_result_t< | |||
2120 | V&&, | |||
2121 | typename detail::traits<detail::select_t<0, T...>>::const_reference, | |||
2122 | detail::alternative_info<0, variant>> | |||
2123 | #else | |||
2124 | DEDUCED | |||
2125 | #endif | |||
2126 | 9 | visit_informed(V&& visitor) const& { | ||
2127 | 9 | return detail::visit_informed_impl<V, const variant&, T...>( | ||
2128 | 9 | std::forward<V>(visitor), *this); | ||
2129 | } | |||
2130 | ||||
2131 | /// @brief Calls a visitor callable with the contained alternative and metadata | |||
2132 | /// | |||
2133 | /// @details | |||
2134 | /// This function calls the visitor as `std::invoke(visitor, alternative, info)`, | |||
2135 | /// and returns the result of that call, if any. As such, `visitor` *must* be | |||
2136 | /// able to accept any alternative type as an argument. In the case of an | |||
2137 | /// alternative of type `void`, the visitor must be callable as | |||
2138 | /// `std::invoke(visitor, void_v, info)`. | |||
2139 | /// | |||
2140 | /// The `info` argument passed to the visitor, which differentiates this | |||
2141 | /// function from `.visit(...)`, communicates `constexpr` information about | |||
2142 | /// the alternative being visited. The type of the `info` object is not | |||
2143 | /// meant to be named, but it has the API shown below. Note that `info` is | |||
2144 | /// always an empty type. | |||
2145 | /// | |||
2146 | /// ``` | |||
2147 | /// struct alternative_info { | |||
2148 | /// // index of the alternative in the source variant | |||
2149 | /// static inline constexpr size_t index = ...; | |||
2150 | /// | |||
2151 | /// // type of the alternative as declared in the source variant | |||
2152 | /// using type = ...; | |||
2153 | /// }; | |||
2154 | /// ``` | |||
2155 | /// | |||
2156 | /// Note that the @ref overload function can be helpful for defining a | |||
2157 | /// visitor inline. | |||
2158 | /// | |||
2159 | /// Also note that this function is implemented as a compile-time-defined | |||
2160 | /// jump table (array of function pointers). In performance critical | |||
2161 | /// applications, be wary of any assumptions about how well or poorly your | |||
2162 | /// compiler will optimize a call to this function. | |||
2163 | /// | |||
2164 | /// ## Example | |||
2165 | /// ``` | |||
2166 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2167 | /// | |||
2168 | /// std::move(v1).visit_informed([](auto value, auto info) { | |||
2169 | /// if constexpr (info.index == 0) { | |||
2170 | /// assert(false); | |||
2171 | /// } else if constexpr (info.index == 1) { | |||
2172 | /// assert(value == 42); | |||
2173 | /// } else if constexpr (info.index == 2) { | |||
2174 | /// assert(false); | |||
2175 | /// } | |||
2176 | /// }); | |||
2177 | /// ``` | |||
2178 | /// | |||
2179 | /// @param visitor The callable object that will be passed an alternative. | |||
2180 | /// @return The return value of the visitor, if any. | |||
2181 | template <typename V> | |||
2182 | constexpr | |||
2183 | #ifndef DOXYGEN | |||
2184 | detail::invoke_result_t< | |||
2185 | V&&, | |||
2186 | typename detail::traits<detail::select_t<0, T...>>::rvalue_reference, | |||
2187 | detail::alternative_info<0, variant>> | |||
2188 | #else | |||
2189 | DEDUCED | |||
2190 | #endif | |||
2191 | 30 | visit_informed(V&& visitor) && { | ||
2192 | 30 | return detail::visit_informed_impl<V, variant&&, T...>(std::forward<V>(visitor), | ||
2193 | 60 | std::move(*this)); | ||
2194 | } | |||
2195 | ||||
2196 | /// @brief Calls a visitor callable with the contained alternative and metadata | |||
2197 | /// | |||
2198 | /// @details | |||
2199 | /// This function calls the visitor as `std::invoke(visitor, alternative, info)`, | |||
2200 | /// and returns the result of that call, if any. As such, `visitor` *must* be | |||
2201 | /// able to accept any alternative type as an argument. In the case of an | |||
2202 | /// alternative of type `void`, the visitor must be callable as | |||
2203 | /// `std::invoke(visitor, void_v, info)`. | |||
2204 | /// | |||
2205 | /// The `info` argument passed to the visitor, which differentiates this | |||
2206 | /// function from `.visit(...)`, communicates `constexpr` information about | |||
2207 | /// the alternative being visited. The type of the `info` object is not | |||
2208 | /// meant to be named, but it has the API shown below. Note that `info` is | |||
2209 | /// always an empty type. | |||
2210 | /// | |||
2211 | /// ``` | |||
2212 | /// struct alternative_info { | |||
2213 | /// // index of the alternative in the source variant | |||
2214 | /// static inline constexpr size_t index = ...; | |||
2215 | /// | |||
2216 | /// // type of the alternative as declared in the source variant | |||
2217 | /// using type = ...; | |||
2218 | /// }; | |||
2219 | /// ``` | |||
2220 | /// | |||
2221 | /// Note that the @ref overload function can be helpful for defining a | |||
2222 | /// visitor inline. | |||
2223 | /// | |||
2224 | /// Also note that this function is implemented as a compile-time-defined | |||
2225 | /// jump table (array of function pointers). In performance critical | |||
2226 | /// applications, be wary of any assumptions about how well or poorly your | |||
2227 | /// compiler will optimize a call to this function. | |||
2228 | /// | |||
2229 | /// ## Example | |||
2230 | /// ``` | |||
2231 | /// const variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2232 | /// | |||
2233 | /// std::move(v1).visit_informed([](auto value, auto info) { | |||
2234 | /// if constexpr (info.index == 0) { | |||
2235 | /// assert(false); | |||
2236 | /// } else if constexpr (info.index == 1) { | |||
2237 | /// assert(value == 42); | |||
2238 | /// } else if constexpr (info.index == 2) { | |||
2239 | /// assert(false); | |||
2240 | /// } | |||
2241 | /// }); | |||
2242 | /// ``` | |||
2243 | /// | |||
2244 | /// @param visitor The callable object that will be passed an alternative. | |||
2245 | /// @return The return value of the visitor, if any. | |||
2246 | template <typename V> | |||
2247 | constexpr | |||
2248 | #ifndef DOXYGEN | |||
2249 | detail::invoke_result_t< | |||
2250 | V&&, | |||
2251 | typename detail::traits<detail::select_t<0, T...>>::const_rvalue_reference, | |||
2252 | detail::alternative_info<0, variant>> | |||
2253 | #else | |||
2254 | DEDUCED | |||
2255 | #endif | |||
2256 | 1 | visit_informed(V&& visitor) const&& { | ||
2257 | 1 | return detail::visit_informed_impl<V, const variant&&, T...>( | ||
2258 | 2 | std::forward<V>(visitor), std::move(*this)); | ||
2259 | } | |||
2260 | ||||
2261 | /// @brief Swaps two @ref variant instances | |||
2262 | /// | |||
2263 | /// @details | |||
2264 | /// If the two @ref variant instances contain the same alternative, the | |||
2265 | /// alternative values are swapped directly. Otherwise, the alternatives | |||
2266 | /// are swapped by moving out of the variants, destroying the old | |||
2267 | /// alternatives, and move constructed into the new alternatives. | |||
2268 | /// | |||
2269 | /// ## Example | |||
2270 | /// ```cpp | |||
2271 | /// variant<bool, int, void> v1{std::in_place_index<0>, true}; | |||
2272 | /// | |||
2273 | /// variant<bool, int, void> v2{std::in_place_index<1>, 42}; | |||
2274 | /// | |||
2275 | /// v1.swap(v2); | |||
2276 | /// | |||
2277 | /// assert(v1.index() == 1); | |||
2278 | /// | |||
2279 | /// assert(get<1>(v1) == 42); | |||
2280 | /// | |||
2281 | /// assert(v2.index() == 0); | |||
2282 | /// | |||
2283 | /// assert(get<2>(v2) == true); | |||
2284 | /// ``` | |||
2285 | /// | |||
2286 | /// @param other The "other" @ref variant to swap with this @ref variant | |||
2287 | 7 | constexpr void swap(variant& other) | ||
2288 | #ifndef DOXYGEN | |||
2289 | noexcept(noexcept(data_().swap(other.data_()))) | |||
2290 | #else | |||
2291 | CONDITIONALLY_NOEXCEPT | |||
2292 | #endif | |||
2293 | { | |||
2294 | 7 | data_().swap(other.data_()); | ||
2295 | 7 | } | ||
2296 | }; | |||
2297 | ||||
2298 | /// @relates variant | |||
2299 | /// @brief Checks if a @ref variant contains a particular alternative. | |||
2300 | /// | |||
2301 | /// @details | |||
2302 | /// Given a type parameter, this function checks if the @ref variant currently | |||
2303 | /// holds an alternative that has the exact same type. | |||
2304 | /// | |||
2305 | /// ## Example | |||
2306 | /// ```cpp | |||
2307 | /// variant<int, bool, int> v1{std::in_place_index<0>, 42}; | |||
2308 | /// | |||
2309 | /// assert(holds_alternative<int>(v1)); | |||
2310 | /// | |||
2311 | /// variant<int, bool, int> v2{std::in_place_index<2>, 42}; | |||
2312 | /// | |||
2313 | /// assert(holds_alternative<int>(v2)); | |||
2314 | /// ``` | |||
2315 | /// | |||
2316 | /// @param v The @ref variant to check. | |||
2317 | /// @return `true` if the @ref variant holds an alternative of the given type. | |||
2318 | template <typename T, typename... U> | |||
2319 | 104 | constexpr bool holds_alternative(const variant<U...>& v) noexcept { | ||
2320 | 104 | return v.template holds_alternative<T>(); | ||
2321 | } | |||
2322 | ||||
2323 | /// @relates variant | |||
2324 | /// @brief Gets a @ref variant alternative by index | |||
2325 | /// | |||
2326 | /// @details | |||
2327 | /// This function allows accessing @ref variant alternatives by index, which is | |||
2328 | /// provided as a template argument. | |||
2329 | /// | |||
2330 | /// ## Example | |||
2331 | /// ```cpp | |||
2332 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2333 | /// | |||
2334 | /// assert(get<1>(v) == 42); | |||
2335 | /// | |||
2336 | /// get<1>(v) = 24; | |||
2337 | /// | |||
2338 | /// assert(get<1>(v) == 24); | |||
2339 | /// ``` | |||
2340 | /// | |||
2341 | /// @tparam I The index of the alternative to access. | |||
2342 | /// | |||
2343 | /// @param v The @ref variant to access | |||
2344 | /// | |||
2345 | /// @return A reference to the accessed alternative, if applicable. | |||
2346 | /// | |||
2347 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2348 | /// the alternative with the corresponding index. | |||
2349 | template <size_t I, typename... T> | |||
2350 | constexpr | |||
2351 | #ifndef DOXYGEN | |||
2352 | typename detail::traits<detail::select_t<I, T...>>::reference | |||
2353 | #else | |||
2354 | REFERENCE | |||
2355 | #endif | |||
2356 | 102 | get(variant<T...>& v) { | ||
2357 | 102 | return v.template get<I>(); | ||
2358 | } | |||
2359 | ||||
2360 | /// @relates variant | |||
2361 | /// @brief Gets a @ref variant alternative by index | |||
2362 | /// | |||
2363 | /// @details | |||
2364 | /// This function allows accessing @ref variant alternatives by index, which is | |||
2365 | /// provided as a template argument. | |||
2366 | /// | |||
2367 | /// ## Example | |||
2368 | /// ```cpp | |||
2369 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2370 | /// | |||
2371 | /// assert(get<1>(v) == 42); | |||
2372 | /// | |||
2373 | /// get<1>(v) = 24; | |||
2374 | /// | |||
2375 | /// assert(get<1>(v) == 24); | |||
2376 | /// ``` | |||
2377 | /// | |||
2378 | /// @tparam I The index of the alternative to access. | |||
2379 | /// | |||
2380 | /// @param v The @ref variant to access | |||
2381 | /// | |||
2382 | /// @return A reference to the accessed alternative, if applicable. | |||
2383 | /// | |||
2384 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2385 | /// the alternative with the corresponding index. | |||
2386 | template <size_t I, typename... T> | |||
2387 | constexpr | |||
2388 | #ifndef DOXYGEN | |||
2389 | typename detail::traits<detail::select_t<I, T...>>::const_reference | |||
2390 | #else | |||
2391 | CONST_REFERENCE | |||
2392 | #endif | |||
2393 | 1 | get(const variant<T...>& v) { | ||
2394 | 1 | return v.template get<I>(); | ||
2395 | } | |||
2396 | ||||
2397 | /// @relates variant | |||
2398 | /// @brief Gets a @ref variant alternative by index | |||
2399 | /// | |||
2400 | /// @details | |||
2401 | /// This function allows accessing @ref variant alternatives by index, which is | |||
2402 | /// provided as a template argument. | |||
2403 | /// | |||
2404 | /// ## Example | |||
2405 | /// ```cpp | |||
2406 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2407 | /// | |||
2408 | /// assert(get<1>(v) == 42); | |||
2409 | /// | |||
2410 | /// get<1>(v) = 24; | |||
2411 | /// | |||
2412 | /// assert(get<1>(v) == 24); | |||
2413 | /// ``` | |||
2414 | /// | |||
2415 | /// @tparam I The index of the alternative to access. | |||
2416 | /// | |||
2417 | /// @param v The @ref variant to access | |||
2418 | /// | |||
2419 | /// @return The accessed alternative value, if applicable. | |||
2420 | /// | |||
2421 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2422 | /// the alternative with the corresponding index. | |||
2423 | template <size_t I, typename... T> | |||
2424 | constexpr | |||
2425 | #ifndef DOXYGEN | |||
2426 | typename detail::traits<detail::select_t<I, T...>>::rvalue_reference | |||
2427 | #else | |||
2428 | RVALUE_REFERENCE | |||
2429 | #endif | |||
2430 | 1 | get(variant<T...>&& v) { | ||
2431 | 1 | return std::move(v).template get<I>(); | ||
2432 | } | |||
2433 | ||||
2434 | /// @relates variant | |||
2435 | /// @brief Gets a @ref variant alternative by index | |||
2436 | /// | |||
2437 | /// @details | |||
2438 | /// This function allows accessing @ref variant alternatives by index, which is | |||
2439 | /// provided as a template argument. | |||
2440 | /// | |||
2441 | /// ## Example | |||
2442 | /// ```cpp | |||
2443 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2444 | /// | |||
2445 | /// assert(get<1>(v) == 42); | |||
2446 | /// | |||
2447 | /// get<1>(v) = 24; | |||
2448 | /// | |||
2449 | /// assert(get<1>(v) == 24); | |||
2450 | /// ``` | |||
2451 | /// | |||
2452 | /// @tparam I The index of the alternative to access. | |||
2453 | /// | |||
2454 | /// @param v The @ref variant to access | |||
2455 | /// | |||
2456 | /// @return The accessed alternative value, if applicable. | |||
2457 | /// | |||
2458 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2459 | /// the alternative with the corresponding index. | |||
2460 | template <size_t I, typename... T> | |||
2461 | constexpr | |||
2462 | #ifndef DOXYGEN | |||
2463 | typename detail::traits<detail::select_t<I, T...>>::const_rvalue_reference | |||
2464 | #else | |||
2465 | CONST_RVALUE_REFERENCE | |||
2466 | #endif | |||
2467 | 1 | get(const variant<T...>&& v) { | ||
2468 | 1 | return std::move(v).template get<I>(); | ||
2469 | } | |||
2470 | ||||
2471 | /// @relates variant | |||
2472 | /// @brief Gets a @ref variant alternative by type | |||
2473 | /// | |||
2474 | /// @details | |||
2475 | /// This function allows accessing @ref variant alternatives by type, which is | |||
2476 | /// provided as a template argument. | |||
2477 | /// | |||
2478 | /// This function only participates in overload resolution if the type is | |||
2479 | /// unique across all alternative types of the @ref variant. That is, | |||
2480 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2481 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2482 | /// type `B`. | |||
2483 | /// | |||
2484 | /// ## Example | |||
2485 | /// ```cpp | |||
2486 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2487 | /// | |||
2488 | /// assert(get<int>(v) == 42); | |||
2489 | /// | |||
2490 | /// get<int>(v) = 24; | |||
2491 | /// | |||
2492 | /// assert(get<int>(v) == 24); | |||
2493 | /// ``` | |||
2494 | /// | |||
2495 | /// @tparam U The type of the alternative to access. | |||
2496 | /// | |||
2497 | /// @param v The @ref variant to access. | |||
2498 | /// | |||
2499 | /// @return A reference to the accessed alternative, if applicable. | |||
2500 | /// | |||
2501 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2502 | /// the alternative with the corresponding type. | |||
2503 | template <typename T, typename... U> | |||
2504 | #ifndef DOXYGEN | |||
2505 | requires detail::is_unique_v<T, U...> | |||
2506 | #endif | |||
2507 | constexpr | |||
2508 | #ifndef DOXYGEN | |||
2509 | typename detail::traits<T>::reference | |||
2510 | #else | |||
2511 | REFERENCE | |||
2512 | #endif | |||
2513 | 24 | get(variant<U...>& v) { | ||
2514 | 24 | return v.template get<T>(); | ||
2515 | } | |||
2516 | ||||
2517 | /// @relates variant | |||
2518 | /// @brief Gets a @ref variant alternative by type | |||
2519 | /// | |||
2520 | /// @details | |||
2521 | /// This function allows accessing @ref variant alternatives by type, which is | |||
2522 | /// provided as a template argument. | |||
2523 | /// | |||
2524 | /// This function only participates in overload resolution if the type is | |||
2525 | /// unique across all alternative types of the @ref variant. That is, | |||
2526 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2527 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2528 | /// type `B`. | |||
2529 | /// | |||
2530 | /// ## Example | |||
2531 | /// ```cpp | |||
2532 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2533 | /// | |||
2534 | /// assert(get<int>(v) == 42); | |||
2535 | /// | |||
2536 | /// get<int>(v) = 24; | |||
2537 | /// | |||
2538 | /// assert(get<int>(v) == 24); | |||
2539 | /// ``` | |||
2540 | /// | |||
2541 | /// @tparam U The type of the alternative to access. | |||
2542 | /// | |||
2543 | /// @param v The @ref variant to access. | |||
2544 | /// | |||
2545 | /// @return A reference to the accessed alternative, if applicable. | |||
2546 | /// | |||
2547 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2548 | /// the alternative with the corresponding type. | |||
2549 | template <typename T, typename... U> | |||
2550 | #ifndef DOXYGEN | |||
2551 | requires detail::is_unique_v<T, U...> | |||
2552 | #endif | |||
2553 | constexpr | |||
2554 | #ifndef DOXYGEN | |||
2555 | typename detail::traits<T>::const_reference | |||
2556 | #else | |||
2557 | CONST_REFERENCE | |||
2558 | #endif | |||
2559 | 1 | get(const variant<U...>& v) { | ||
2560 | 1 | return v.template get<T>(); | ||
2561 | } | |||
2562 | ||||
2563 | /// @relates variant | |||
2564 | /// @brief Gets a @ref variant alternative by type | |||
2565 | /// | |||
2566 | /// @details | |||
2567 | /// This function allows accessing @ref variant alternatives by type, which is | |||
2568 | /// provided as a template argument. | |||
2569 | /// | |||
2570 | /// This function only participates in overload resolution if the type is | |||
2571 | /// unique across all alternative types of the @ref variant. That is, | |||
2572 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2573 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2574 | /// type `B`. | |||
2575 | /// | |||
2576 | /// ## Example | |||
2577 | /// ```cpp | |||
2578 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2579 | /// | |||
2580 | /// assert(get<int>(v) == 42); | |||
2581 | /// | |||
2582 | /// get<int>(v) = 24; | |||
2583 | /// | |||
2584 | /// assert(get<int>(v) == 24); | |||
2585 | /// ``` | |||
2586 | /// | |||
2587 | /// @tparam U The type of the alternative to access. | |||
2588 | /// | |||
2589 | /// @param v The @ref variant to access. | |||
2590 | /// | |||
2591 | /// @return The accessed alternative value, if applicable. | |||
2592 | /// | |||
2593 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2594 | /// the alternative with the corresponding type. | |||
2595 | template <typename T, typename... U> | |||
2596 | #ifndef DOXYGEN | |||
2597 | requires detail::is_unique_v<T, U...> | |||
2598 | #endif | |||
2599 | constexpr | |||
2600 | #ifndef DOXYGEN | |||
2601 | typename detail::traits<T>::rvalue_reference | |||
2602 | #else | |||
2603 | RVALUE_REFERENCE | |||
2604 | #endif | |||
2605 | 1 | get(variant<U...>&& v) { | ||
2606 | 1 | return std::move(v).template get<T>(); | ||
2607 | } | |||
2608 | ||||
2609 | /// @relates variant | |||
2610 | /// @brief Gets a @ref variant alternative by type | |||
2611 | /// | |||
2612 | /// @details | |||
2613 | /// This function allows accessing @ref variant alternatives by type, which is | |||
2614 | /// provided as a template argument. | |||
2615 | /// | |||
2616 | /// This function only participates in overload resolution if the type is | |||
2617 | /// unique across all alternative types of the @ref variant. That is, | |||
2618 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2619 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2620 | /// type `B`. | |||
2621 | /// | |||
2622 | /// ## Example | |||
2623 | /// ```cpp | |||
2624 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2625 | /// | |||
2626 | /// assert(get<int>(v) == 42); | |||
2627 | /// | |||
2628 | /// get<int>(v) = 24; | |||
2629 | /// | |||
2630 | /// assert(get<int>(v) == 24); | |||
2631 | /// ``` | |||
2632 | /// | |||
2633 | /// @tparam U The type of the alternative to access. | |||
2634 | /// | |||
2635 | /// @param v The @ref variant to access. | |||
2636 | /// | |||
2637 | /// @return The accessed alternative value, if applicable. | |||
2638 | /// | |||
2639 | /// @throws bad_variant_access Thrown if the @ref variant does not contain | |||
2640 | /// the alternative with the corresponding type. | |||
2641 | template <typename T, typename... U> | |||
2642 | #ifndef DOXYGEN | |||
2643 | requires detail::is_unique_v<T, U...> | |||
2644 | #endif | |||
2645 | constexpr | |||
2646 | #ifndef DOXYGEN | |||
2647 | typename detail::traits<T>::const_rvalue_reference | |||
2648 | #else | |||
2649 | CONST_RVALUE_REFERENCE | |||
2650 | #endif | |||
2651 | 1 | get(const variant<U...>&& v) { | ||
2652 | 1 | return std::move(v).template get<T>(); | ||
2653 | } | |||
2654 | ||||
2655 | /// @relates variant | |||
2656 | /// @brief Gets a @ref variant alternative pointer by index if the @ref variant holds it | |||
2657 | /// | |||
2658 | /// @details | |||
2659 | /// This functions tries to access a @ref variant alternative by index. If the | |||
2660 | /// @ref variant contains the alternative, this function returns a pointer to | |||
2661 | /// the alternative, if applicable. If the @ref variant does not contain the | |||
2662 | /// alternative, this function returns null. In the case where the alternative | |||
2663 | /// is of type `void`, this function does nothing. | |||
2664 | /// | |||
2665 | /// ## Example | |||
2666 | /// ```cpp | |||
2667 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2668 | /// | |||
2669 | /// assert(*get_if<1>(v) == 42); | |||
2670 | /// | |||
2671 | /// *get_if<1>(v) = 24; | |||
2672 | /// | |||
2673 | /// assert(*get_if<1>(v) == 24); | |||
2674 | /// | |||
2675 | /// assert(get_if<0>(v) == nullptr); | |||
2676 | /// ``` | |||
2677 | /// | |||
2678 | /// @tparam I The index of the alternative to access. | |||
2679 | /// | |||
2680 | /// @param v The @ref variant to access | |||
2681 | /// | |||
2682 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
2683 | template <size_t I, typename... T> | |||
2684 | constexpr | |||
2685 | #ifndef DOXYGEN | |||
2686 | typename detail::traits<detail::select_t<I, T...>>::pointer | |||
2687 | #else | |||
2688 | POINTER | |||
2689 | #endif | |||
2690 | 26 | get_if(variant<T...>& v) noexcept { | ||
2691 | 26 | return v.template get_if<I>(); | ||
2692 | } | |||
2693 | ||||
2694 | /// @relates variant | |||
2695 | /// @brief Gets a @ref variant alternative pointer by index if the @ref variant holds it | |||
2696 | /// | |||
2697 | /// @details | |||
2698 | /// This functions tries to access a @ref variant alternative by index. If the | |||
2699 | /// @ref variant contains the alternative, this function returns a pointer to | |||
2700 | /// the alternative, if applicable. If the @ref variant does not contain the | |||
2701 | /// alternative, this function returns null. In the case where the alternative | |||
2702 | /// is of type `void`, this function does nothing. | |||
2703 | /// | |||
2704 | /// ## Example | |||
2705 | /// ```cpp | |||
2706 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2707 | /// | |||
2708 | /// assert(*get_if<1>(v) == 42); | |||
2709 | /// | |||
2710 | /// *get_if<1>(v) = 24; | |||
2711 | /// | |||
2712 | /// assert(*get_if<1>(v) == 24); | |||
2713 | /// | |||
2714 | /// assert(get_if<0>(v) == nullptr); | |||
2715 | /// ``` | |||
2716 | /// | |||
2717 | /// @tparam I The index of the alternative to access. | |||
2718 | /// | |||
2719 | /// @param v The @ref variant to access | |||
2720 | /// | |||
2721 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
2722 | template <size_t I, typename... T> | |||
2723 | constexpr | |||
2724 | #ifndef DOXYGEN | |||
2725 | typename detail::traits<detail::select_t<I, T...>>::const_pointer | |||
2726 | #else | |||
2727 | CONST_POINTER | |||
2728 | #endif | |||
2729 | 8 | get_if(const variant<T...>& v) noexcept { | ||
2730 | 8 | return v.template get_if<I>(); | ||
2731 | } | |||
2732 | ||||
2733 | /// @relates variant | |||
2734 | /// @brief Gets a @ref variant alternative pointer by type if the @ref variant holds it | |||
2735 | /// | |||
2736 | /// @details | |||
2737 | /// This functions tries to access an alternative by type. If the @ref variant | |||
2738 | /// contains the alternative, this function returns a pointer to the | |||
2739 | /// alternative, if applicable. If the @ref variant does not contain the | |||
2740 | /// alternative, this function returns null. In the case where the alternative | |||
2741 | /// is of type `void`, this function does nothing. | |||
2742 | /// | |||
2743 | /// This function only participates in overload resolution if the type is | |||
2744 | /// unique across all alternative types of the @ref variant. That is, | |||
2745 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2746 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2747 | /// type `B`. | |||
2748 | /// | |||
2749 | /// ## Example | |||
2750 | /// ```cpp | |||
2751 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2752 | /// | |||
2753 | /// assert(*get_if<int>(v) == 42); | |||
2754 | /// | |||
2755 | /// *get_if<int>(v) = 24; | |||
2756 | /// | |||
2757 | /// assert(*get_if<int>(v) == 24); | |||
2758 | /// | |||
2759 | /// assert(get_if<bool>(v) == nullptr); | |||
2760 | /// ``` | |||
2761 | /// | |||
2762 | /// @tparam I The index of the alternative to access. | |||
2763 | /// | |||
2764 | /// @param v The @ref variant to access. | |||
2765 | /// | |||
2766 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
2767 | template <typename T, typename... U> | |||
2768 | #ifndef DOXYGEN | |||
2769 | requires detail::is_unique_v<T, U...> | |||
2770 | #endif | |||
2771 | constexpr | |||
2772 | #ifndef DOXYGEN | |||
2773 | typename detail::traits<T>::pointer | |||
2774 | #else | |||
2775 | POINTER | |||
2776 | #endif | |||
2777 | 26 | get_if(variant<U...>& v) noexcept { | ||
2778 | 26 | return v.template get_if<T>(); | ||
2779 | } | |||
2780 | ||||
2781 | /// @relates variant | |||
2782 | /// @brief Gets a @ref variant alternative pointer by type if the @ref variant holds it | |||
2783 | /// | |||
2784 | /// @details | |||
2785 | /// This functions tries to access an alternative by type. If the @ref variant | |||
2786 | /// contains the alternative, this function returns a pointer to the | |||
2787 | /// alternative, if applicable. If the @ref variant does not contain the | |||
2788 | /// alternative, this function returns null. In the case where the alternative | |||
2789 | /// is of type `void`, this function does nothing. | |||
2790 | /// | |||
2791 | /// This function only participates in overload resolution if the type is | |||
2792 | /// unique across all alternative types of the @ref variant. That is, | |||
2793 | /// `variant<A, B, A>` cannot use this function to access an alternative | |||
2794 | /// of type `A`, but it can use this fucntion to access an alternative of | |||
2795 | /// type `B`. | |||
2796 | /// | |||
2797 | /// ## Example | |||
2798 | /// ```cpp | |||
2799 | /// variant<bool, int, void> v{std::in_place_index<1>, 42}; | |||
2800 | /// | |||
2801 | /// assert(*get_if<int>(v) == 42); | |||
2802 | /// | |||
2803 | /// *get_if<int>(v) = 24; | |||
2804 | /// | |||
2805 | /// assert(*get_if<int>(v) == 24); | |||
2806 | /// | |||
2807 | /// assert(get_if<bool>(v) == nullptr); | |||
2808 | /// ``` | |||
2809 | /// | |||
2810 | /// @tparam I The index of the alternative to access. | |||
2811 | /// | |||
2812 | /// @param v The @ref variant to access. | |||
2813 | /// | |||
2814 | /// @return A pointer to the accessed alternative, if applicable, or null | |||
2815 | template <typename T, typename... U> | |||
2816 | #ifndef DOXYGEN | |||
2817 | requires detail::is_unique_v<T, U...> | |||
2818 | #endif | |||
2819 | constexpr | |||
2820 | #ifndef DOXYGEN | |||
2821 | typename detail::traits<T>::const_pointer | |||
2822 | #else | |||
2823 | CONST_POINTER | |||
2824 | #endif | |||
2825 | 8 | get_if(const variant<U...>& v) noexcept { | ||
2826 | 8 | return v.template get_if<T>(); | ||
2827 | } | |||
2828 | ||||
2829 | /// @relates variant | |||
2830 | /// @brief Calls a visitor callable with the contained @ref variant alternatives | |||
2831 | /// | |||
2832 | /// @details | |||
2833 | /// This function calls the visitor as `std::invoke(visitor, alternative...)` | |||
2834 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
2835 | /// be able to accecpt any combination of alternative types as arguments. In | |||
2836 | /// the case of an alternative type `void`, the visitor must accept nothing | |||
2837 | /// for that argument. That is, the alternative type combination | |||
2838 | /// `int, void, int`, would result in the visitor being called as | |||
2839 | /// `std::invoke(visitor, int_value, int_value)`, essentially skipping the | |||
2840 | /// `void` alternative. | |||
2841 | /// | |||
2842 | /// Note that the @ref overload function can be helpful for defining a | |||
2843 | /// visitor inline. | |||
2844 | /// | |||
2845 | /// Also note that this function is implemented as a compile-time-defined | |||
2846 | /// jump table (array of function pointers). In performance critical | |||
2847 | /// applications, be wary of any assumptions about how well or poorly your | |||
2848 | /// compiler will optimize a call to this function. | |||
2849 | /// | |||
2850 | /// ## Example | |||
2851 | /// ```cpp | |||
2852 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2853 | /// variant<float, int> v2{std::in_place_index<0>, 3.14}; | |||
2854 | /// | |||
2855 | /// visit(overload( | |||
2856 | /// [](bool val1, float val2) { assert(false); }, | |||
2857 | /// [](int val1, float val2) { assert(val1 == 42); }, | |||
2858 | /// [](float val2) { assert(false); }, | |||
2859 | /// [](bool val1, int val2) { assert(false); }, | |||
2860 | /// [](int val1, float val2) { assert(false); }, | |||
2861 | /// [](int val2) { assert(false); } | |||
2862 | /// ), v1, v2); | |||
2863 | /// ``` | |||
2864 | /// | |||
2865 | /// @param visitor The callable object that will be passed an alternative. | |||
2866 | /// | |||
2867 | /// @return The return value of the visitor, if any. | |||
2868 | template <typename V> | |||
2869 | constexpr | |||
2870 | #ifndef DOXYGEN | |||
2871 | std::invoke_result_t<V&&> | |||
2872 | #else | |||
2873 | DEDUCED | |||
2874 | #endif | |||
2875 | 1 | visit(V&& visitor) { | ||
2876 | 1 | return std::invoke(std::forward<V>(visitor)); | ||
2877 | } | |||
2878 | ||||
2879 | /// @relates variant | |||
2880 | /// @brief Calls a visitor callable with the contained @ref variant alternatives | |||
2881 | /// | |||
2882 | /// @details | |||
2883 | /// This function calls the visitor as `std::invoke(visitor, alternative...)` | |||
2884 | /// and returns the result of that call, if any. As such, `visitor` *must* | |||
2885 | /// be able to accecpt any combination of alternative types as arguments. In | |||
2886 | /// the case of an alternative type `void`, the visitor must accept nothing | |||
2887 | /// for that argument. That is, the alternative type combination | |||
2888 | /// `int, void, int`, would result in the visitor being called as | |||
2889 | /// `std::invoke(visitor, int_value, int_value)`, essentially skipping the | |||
2890 | /// `void` alternative. | |||
2891 | /// | |||
2892 | /// Note that the @ref overload function can be helpful for defining a | |||
2893 | /// visitor inline. | |||
2894 | /// | |||
2895 | /// Also note that this function is implemented as a compile-time-defined | |||
2896 | /// jump table (array of function pointers). In performance critical | |||
2897 | /// applications, be wary of any assumptions about how well or poorly your | |||
2898 | /// compiler will optimize a call to this function. | |||
2899 | /// | |||
2900 | /// ## Example | |||
2901 | /// ```cpp | |||
2902 | /// variant<bool, int, void> v1{std::in_place_index<1>, 42}; | |||
2903 | /// variant<float, int> v2{std::in_place_index<0>, 3.14}; | |||
2904 | /// | |||
2905 | /// visit(overload( | |||
2906 | /// [](bool val1, float val2) { assert(false); }, | |||
2907 | /// [](int val1, float val2) { assert(val1 == 42); }, | |||
2908 | /// [](float val2) { assert(false); }, | |||
2909 | /// [](bool val1, int val2) { assert(false); }, | |||
2910 | /// [](int val1, float val2) { assert(false); }, | |||
2911 | /// [](int val2) { assert(false); } | |||
2912 | /// ), v1, v2); | |||
2913 | /// ``` | |||
2914 | /// | |||
2915 | /// @param visitor The callable object that will be passed an alternative. | |||
2916 | /// | |||
2917 | /// @param var0 The first variant to visit | |||
2918 | /// | |||
2919 | /// @param varn The remaining variant to visit | |||
2920 | /// | |||
2921 | /// @return The return value of the visitor, if any. | |||
2922 | template <typename V, typename T0, typename... TN> | |||
2923 | constexpr | |||
2924 | #ifndef DOXYGEN | |||
2925 | detail::invoke_result_t<V&&, | |||
2926 | decltype(get<0>(std::declval<T0&&>())), | |||
2927 | decltype(get<0>(std::declval<TN&&>()))...> | |||
2928 | #else | |||
2929 | DEDUCED | |||
2930 | #endif | |||
2931 | // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) | |||
2932 | 23 | visit(V&& visitor, T0&& var0, TN&&... varn) { | ||
2933 | if constexpr (sizeof...(TN) == 0) { | |||
2934 | 17 | return std::forward<T0>(var0).visit(std::forward<V>(visitor)); | ||
2935 | } else { | |||
2936 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
18 | return std::forward<T0>(var0).visit( | |
2937 | 11 | [visitor = std::forward<V>(visitor), | ||
2938 | 6 | ... varn = std::forward<TN>(varn)](auto&&... value) mutable { | ||
2939 |
2/18✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
|
10 | return visit( | |
2940 | 10 | [visitor = std::forward<V>(visitor), | ||
2941 | 5 | ... value = std::forward<decltype(value)>(value)]( | ||
2942 | auto&&... args) mutable -> decltype(auto) { | |||
2943 | 10 | return std::invoke(std::forward<V>(visitor), | ||
2944 | 5 | std::forward<decltype(value)>(value)..., | ||
2945 | 5 | std::forward<decltype(args)>(args)...); | ||
2946 | }, | |||
2947 | 15 | std::forward<TN>(varn)...); | ||
2948 | 12 | }); | ||
2949 | } | |||
2950 | } | |||
2951 | ||||
2952 | /// @relates variant | |||
2953 | /// @brief Swaps two @ref variant instances | |||
2954 | /// | |||
2955 | /// @details | |||
2956 | /// If the two @ref variant instances contain the same alternative, the | |||
2957 | /// alternative values are swapped directly. Otherwise, the alternatives | |||
2958 | /// are swapped by moving out of the variants, destroying the old | |||
2959 | /// alternatives, and move constructed into the new alternatives. | |||
2960 | /// | |||
2961 | /// ## Example | |||
2962 | /// ```cpp | |||
2963 | /// variant<bool, int, void> v1{std::in_place_index<0>, true}; | |||
2964 | /// | |||
2965 | /// variant<bool, int, void> v2{std::in_place_index<1>, 42}; | |||
2966 | /// | |||
2967 | /// swap(v1, v2); | |||
2968 | /// | |||
2969 | /// assert(v1.index() == 1); | |||
2970 | /// | |||
2971 | /// assert(get<1>(v1) == 42); | |||
2972 | /// | |||
2973 | /// assert(v2.index() == 0); | |||
2974 | /// | |||
2975 | /// assert(get<2>(v2) == true); | |||
2976 | /// ``` | |||
2977 | /// | |||
2978 | /// @param a The first variant in the swap | |||
2979 | /// @param b The second variant in the swap | |||
2980 | template <typename... T> | |||
2981 | 4 | constexpr void swap(variant<T...>& a, variant<T...>& b) | ||
2982 | #ifndef DOXYGEN | |||
2983 | noexcept(noexcept(a.swap(b))) | |||
2984 | #else | |||
2985 | CONDITIONALLY_NOEXCEPT | |||
2986 | #endif | |||
2987 | { | |||
2988 | 4 | a.swap(b); | ||
2989 | 4 | } | ||
2990 | ||||
2991 | /// @relates variant | |||
2992 | /// @class variant_size variant.hpp <sumty/variant.hpp> | |||
2993 | /// @brief Utility to get the number of alternatives in a @ref variant | |||
2994 | /// | |||
2995 | /// @details | |||
2996 | /// @ref varaint_size provides the number alternatives in the @ref variant, | |||
2997 | /// `T`, in the static constexpr member `value`. | |||
2998 | /// | |||
2999 | /// ## Example | |||
3000 | /// ```cpp | |||
3001 | /// assert(variant_size<variant<bool, int, void>>::value == 3); | |||
3002 | /// ``` | |||
3003 | /// | |||
3004 | /// @tparam T The @ref variant type to get the size of | |||
3005 | template <typename T> | |||
3006 | struct variant_size | |||
3007 | #ifndef DOXYGEN | |||
3008 | : detail::variant_size_helper<T> { | |||
3009 | }; | |||
3010 | #else | |||
3011 | ; | |||
3012 | #endif | |||
3013 | ||||
3014 | /// @relates variant_size | |||
3015 | /// @brief Utility to get the number of alternatives in a @ref variant | |||
3016 | /// | |||
3017 | /// @details | |||
3018 | /// @ref varaint_size_v provides the number alternatives in the @ref variant, | |||
3019 | /// `T`. | |||
3020 | /// | |||
3021 | /// ## Example | |||
3022 | /// ```cpp | |||
3023 | /// assert(variant_size_v<variant<bool, int, void>> == 3); | |||
3024 | /// ``` | |||
3025 | /// | |||
3026 | /// @tparam T The @ref variant type to get the size of | |||
3027 | template <typename T> | |||
3028 | static inline constexpr size_t variant_size_v = variant_size<T>::value; | |||
3029 | ||||
3030 | /// @relates variant | |||
3031 | /// @class variant_alternative variant.hpp <sumty/variant.hpp> | |||
3032 | /// @brief Utility to get the type of a @ref variant alternative with some index | |||
3033 | /// | |||
3034 | /// @details | |||
3035 | /// @ref variant_alternative provides the type of an alternative with the | |||
3036 | /// index `I` in the member type, `type`. | |||
3037 | /// | |||
3038 | /// ## Example | |||
3039 | /// ```cpp | |||
3040 | /// assert(std::is_same_v< | |||
3041 | /// typename variant_alternative<1, variant<bool, int, void>>::type, | |||
3042 | /// int | |||
3043 | /// >); | |||
3044 | /// ``` | |||
3045 | /// | |||
3046 | /// @tparam I The index of the @ref variant alternative | |||
3047 | /// | |||
3048 | /// @tparam T The @ref variant type containing the alternative | |||
3049 | template <size_t I, typename T> | |||
3050 | struct variant_alternative | |||
3051 | #ifndef DOXYGEN | |||
3052 | : detail::variant_alternative_helper<I, T> { | |||
3053 | }; | |||
3054 | #else | |||
3055 | ; | |||
3056 | #endif | |||
3057 | ||||
3058 | /// @relates variant_alternative | |||
3059 | /// @brief Utility to get the type of a @ref variant alternative with some index | |||
3060 | /// | |||
3061 | /// @details | |||
3062 | /// @ref variant_alternative_t is the type of an alternative with the index `I`. | |||
3063 | /// | |||
3064 | /// ## Example | |||
3065 | /// ```cpp | |||
3066 | /// assert(std::is_same_v< | |||
3067 | /// variant_alternative_t<1, variant<bool, int, void>>, int>); | |||
3068 | /// ``` | |||
3069 | /// | |||
3070 | /// @tparam I The index of the @variant alternative | |||
3071 | /// | |||
3072 | /// @tparam T The @ref variant type containing the alternative | |||
3073 | template <size_t I, typename T> | |||
3074 | using variant_alternative_t = typename variant_alternative<I, T>::type; | |||
3075 | ||||
3076 | /// @private | |||
3077 | template <typename... T> | |||
3078 | requires((true && ... && std::is_base_of_v<never, std::remove_cvref_t<T>>)) | |||
3079 | class variant<T...> : public never {}; | |||
3080 | ||||
3081 | } // namespace sumty | |||
3082 | ||||
3083 | #endif | |||
3084 |