Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
variant.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_VARIANT_VARIANT_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_VARIANT_VARIANT_HPP_
7
8// IWYU pragma: private, include "arene/base/variant.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
12
13// parasoft-begin-suppress AUTOSAR-A16_2_2-a "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
14
15#include "arene/base/array/array.hpp"
16#include "arene/base/byte/byte.hpp"
17#include "arene/base/compare/operators.hpp"
18#include "arene/base/compiler_support/diagnostics.hpp"
19#include "arene/base/compiler_support/platform_queries.hpp"
20#include "arene/base/compiler_support/preprocessor.hpp"
21#include "arene/base/constraints/constraints.hpp"
22#include "arene/base/detail/exceptions.hpp"
23#include "arene/base/memory/construct_at.hpp"
24#include "arene/base/memory/destroy_at.hpp"
25#include "arene/base/stdlib_choice/add_pointer.hpp"
26#include "arene/base/stdlib_choice/addressof.hpp"
27#include "arene/base/stdlib_choice/cstddef.hpp"
28#include "arene/base/stdlib_choice/decay.hpp"
29#include "arene/base/stdlib_choice/declval.hpp"
30#include "arene/base/stdlib_choice/enable_if.hpp"
31#include "arene/base/stdlib_choice/equal_to.hpp"
32#include "arene/base/stdlib_choice/forward.hpp"
33#include "arene/base/stdlib_choice/ignore.hpp"
34#include "arene/base/stdlib_choice/initializer_list.hpp"
35#include "arene/base/stdlib_choice/integral_constant.hpp"
36#include "arene/base/stdlib_choice/is_constructible.hpp"
37#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
38#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
39#include "arene/base/stdlib_choice/is_default_constructible.hpp"
40#include "arene/base/stdlib_choice/is_move_assignable.hpp"
41#include "arene/base/stdlib_choice/is_move_constructible.hpp"
42#include "arene/base/stdlib_choice/is_reference.hpp"
43#include "arene/base/stdlib_choice/is_same.hpp"
44#include "arene/base/stdlib_choice/is_void.hpp"
45#include "arene/base/stdlib_choice/less.hpp"
46#include "arene/base/stdlib_choice/max_initializer_list_overload.hpp" // IWYU pragma: keep
47#include "arene/base/type_traits/conditional.hpp"
48// IWYU pragma: no_include "arene/base/stdlib_choice/max_value_overload.hpp"
49#include "arene/base/stdlib_choice/move.hpp"
50#include "arene/base/stdlib_choice/remove_reference.hpp"
51#include "arene/base/type_list/at.hpp"
52#include "arene/base/type_list/type_list.hpp"
53#include "arene/base/type_manipulation/non_constructible_dummy.hpp"
54#include "arene/base/type_traits/all_of.hpp"
55#include "arene/base/type_traits/index_of.hpp"
56#include "arene/base/type_traits/void_t.hpp"
57#include "arene/base/utility/forward_like.hpp"
58#include "arene/base/variant/traits.hpp"
59
60#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED)
61#include "arene/base/variant/detail/bad_variant_access_exceptions_enabled.hpp" // IWYU pragma: export
62#else
63#include "arene/base/variant/detail/bad_variant_access_exceptions_disabled.hpp" // IWYU pragma: export
64#endif
65
66// parasoft-end-suppress AUTOSAR-A16_2_2-a
67
68// parasoft-begin-suppress AUTOSAR-M2_10_1-a "Similar identifiers permitted by M2-10-1 Permit #1 v1.0.0"
69
70// parasoft-begin-suppress AUTOSAR-A15_5_3-h-2 "False positive: Exception specification is conditional"
71// parasoft-begin-suppress CERT_CPP-ERR50-h "False positive: Exception specification is conditional"
72// parasoft-begin-suppress CERT_CPP-ERR55-a "False positive: Exception specification is conditional"
73
74// parasoft-begin-suppress CERT_CPP-ERR51-b "False positive: Thrown exception is propagated"
75// parasoft-begin-suppress AUTOSAR-A15_3_2-a "False positive: Thrown exception is propagated"
76// parasoft-begin-suppress AUTOSAR-A15_5_3-g "False positive: Thrown exception is propagated"
77// parasoft-begin-suppress CERT_CPP-ERR50-g "False positive: Thrown exception is propagated"
78// parasoft-begin-suppress AUTOSAR-M15_3_4-b "False positive: Thrown exception is propagated"
79// parasoft-begin-suppress AUTOSAR-A15_2_1-b "False positive: Throwing constructor not invoked before program startup"
80
81namespace arene {
82namespace base {
83template <typename... Ts>
84class variant;
85
86namespace variant_detail {
87
88/// @brief A utility class to recursively destroy/copy/move an object with the correct type base on the index of the
89/// type in the variant.
90/// @note This class should only be used when the type of the object to be constructed is unknown at compile time.
91/// Otherwise, @c construct_at should be used.
92/// @tparam Ts variadic template type argument of the types
93template <typename... Ts>
94class variant_util_impl;
95
96// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
97/// @brief copy construct @c T object from @c source to @c dest if @c selected is true
98/// @tparam T type of object
99/// @param selected enables the operation, otherwise function is no-op
100/// @param source pointer to the source object
101/// @param dest pointer to the destination object
102template <typename T>
103inline constexpr void copy_construct_object(bool selected, void const* source, void* dest) noexcept(
104 std::is_copy_constructible<T>::value
105) {
106 static_assert(std::is_copy_constructible<T>::value, "Type must be copyable");
107 if (selected) {
108 construct_at(static_cast<T*>(dest), *static_cast<T const*>(source));
109 }
110}
111// parasoft-end-suppress AUTOSAR-M3_3_2-a
112
113// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
114/// @brief copy assign @c T object from @c source to @c dest if @c selected is true
115/// @tparam T type of object
116/// @param selected enables the operation, otherwise function is no-op
117/// @param source pointer to the source object
118/// @param dest pointer to the destination object
119template <typename T>
120inline constexpr void copy_assign_object(bool selected, void const* source, void* dest) noexcept(
121 std::is_nothrow_copy_assignable<T>::value
122) {
123 static_assert(std::is_copy_assignable<T>::value, "Type must be copy-assignable");
124 if (selected) {
125 *static_cast<T*>(dest) = *static_cast<T const*>(source);
126 }
127}
128// parasoft-end-suppress AUTOSAR-M3_3_2-a
129
130// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
131/// @brief move construct @c T object from @c source to @c dest if @c selected is true
132/// @tparam T type of object
133/// @param selected enables the operation, otherwise function is no-op
134/// @param source pointer to the source object
135/// @param dest pointer to the destination object
136template <typename T>
137inline constexpr void move_construct_object(bool selected, void* source, void* dest) noexcept(
138 std::is_move_constructible<T>::value
139) {
140 static_assert(std::is_move_constructible<T>::value, "Type must be movable");
141 if (selected) {
142 construct_at(static_cast<T*>(dest), static_cast<std::remove_reference_t<T>&&>(*static_cast<T*>(source)));
143 }
144}
145// parasoft-end-suppress AUTOSAR-M3_3_2-a
146
147// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
148/// @brief move assign @c T object from @c source to @c dest if @c selected is true
149/// @tparam T type of object
150/// @param selected enables the operation, otherwise function is no-op
151/// @param source pointer to the source object
152/// @param dest pointer to the destination object
153template <typename T>
154inline constexpr void move_assign_object(bool selected, void* source, void* dest) noexcept(
155 std::is_move_assignable<T>::value
156) {
157 static_assert(std::is_move_assignable<T>::value, "Type must be copy-assignable");
158 if (selected) {
159 *static_cast<T*>(dest) = static_cast<std::remove_reference_t<T>&&>(*static_cast<T*>(source));
160 }
161}
162// parasoft-end-suppress AUTOSAR-M3_3_2-a
163
164// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
165/// @brief destroy object @c T object at @c data if @c selected is true
166/// @tparam T type of object
167/// @param selected enables the operation, otherwise function is no-op
168/// @param data address of object to destroy
169template <typename T>
170inline constexpr void destroy_object(bool selected, void* data) noexcept {
171 if (selected) {
172 destroy_at(static_cast<T*>(data));
173 }
174}
175// parasoft-end-suppress AUTOSAR-M3_3_2-a
176
177// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
178/// @brief check objects pointed at @c lhs and @c rhs of type @c T for equality if @c selected is true
179/// @tparam T type of object
180/// @param selected enables the operation, otherwise function is no-op
181/// @param lhs pointer to the object on left
182/// @param rhs pointer to the object on right
183/// @return true if @c selected is true and objects @c rhs and @c lhs are equal
184template <typename T>
185inline constexpr auto check_object_equality(bool selected, void const* lhs, void const* rhs) noexcept -> bool {
186 if (!selected) {
187 return false;
188 }
189
190 return std::equal_to<T>{}(*static_cast<T const*>(lhs), *static_cast<T const*>(rhs));
191}
192// parasoft-end-suppress AUTOSAR-M3_3_2-a
193
194// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
195/// @brief check objects pointed at @c lhs and @c rhs of type @c T for less-than ordering if @c selected is true
196/// @tparam T type of object
197/// @param selected enables the operation, otherwise function is no-op
198/// @param lhs pointer to the object on left
199/// @param rhs pointer to the object on right
200/// @return true if @c selected is true and object @c lhs is less-than object @c rhs
201template <typename T>
202inline constexpr auto check_object_less_than(bool selected, void const* lhs, void const* rhs) noexcept -> bool {
203 if (!selected) {
204 return false;
205 }
206
207 return std::less<T>{}(*static_cast<T const*>(lhs), *static_cast<T const*>(rhs));
208}
209// parasoft-end-suppress AUTOSAR-M3_3_2-a
210
211/// @brief Recursive specialization of @c variant_util_impl
212/// @tparam T template type argument to be processed recursively with member functions
213/// @tparam Ts variadic template type argument of the types
214template <typename T, typename... Ts>
215class variant_util_impl<T, Ts...> {
216 public:
217 /// @brief Copy construct the object from @c source to @c dest if @c current_idx is equal to @c requested_idx.
218 /// Placement new is used to copy construct the object.
219 /// @param current_idx the index in @c Ts of the current type
220 /// @param requested_idx the index in @c Ts of the type to be copied
221 /// @param source pointer to the source object
222 /// @param dest pointer to the destination object
223 static constexpr void
224 copy(std::size_t current_idx, std::size_t requested_idx, void const* source, void* dest) noexcept(
225 (std::is_nothrow_copy_constructible<T>::value) &&
226 (base::all_of_v<(std::is_nothrow_copy_constructible<Ts>::value)...>)
227 ) {
228 copy_construct_object<T>(current_idx == requested_idx, source, dest);
229 variant_util_impl<Ts...>::copy(current_idx + 1U, requested_idx, source, dest);
230 }
231
232 /// @brief Copy assign the object from @c source to @c dest if @c current_idx is equal to @c requested_idx.
233 /// @param current_idx the index in @c Ts of the current type
234 /// @param requested_idx the index in @c Ts of the type to be copied
235 /// @param source pointer to the source object
236 /// @param dest pointer to the destination object
237 static constexpr void
238 copy_assign(std::size_t current_idx, std::size_t requested_idx, void const* source, void* dest) noexcept(
239 (std::is_nothrow_copy_assignable<T>::value) && (base::all_of_v<(std::is_nothrow_copy_assignable<Ts>::value)...>)
240 ) {
241 copy_assign_object<T>(current_idx == requested_idx, source, dest);
242 variant_util_impl<Ts...>::copy_assign(current_idx + 1U, requested_idx, source, dest);
243 }
244
245 /// @brief Move construct the object from @c source to @c dest if @c current_idx is equal to @c requested_idx.
246 /// Placement new is used to move construct the object.
247 /// @param current_idx the index in @c Ts of the current type
248 /// @param requested_idx the index in @c Ts of the type to be moved
249 /// @param source pointer to the source object
250 /// @param dest pointer to the destination object
251 static constexpr void move(std::size_t current_idx, std::size_t requested_idx, void* source, void* dest) noexcept(
252 (std::is_nothrow_move_constructible<T>::value) &&
253 (base::all_of_v<(std::is_nothrow_move_constructible<Ts>::value)...>)
254 ) {
255 move_construct_object<T>(current_idx == requested_idx, source, dest);
256 variant_util_impl<Ts...>::move(current_idx + 1U, requested_idx, source, dest);
257 }
258
259 /// @brief Move assign the object from @c source to @c dest if @c current_idx is equal to @c requested_idx.
260 /// @param current_idx the index in @c Ts of the current type
261 /// @param requested_idx the index in @c Ts of the type to be moved
262 /// @param source pointer to the source object
263 /// @param dest pointer to the destination object
264 static constexpr void
265 move_assign(std::size_t current_idx, std::size_t requested_idx, void* source, void* dest) noexcept(
266 (std::is_nothrow_move_assignable<T>::value) && (base::all_of_v<(std::is_nothrow_move_assignable<Ts>::value)...>)
267 ) {
268 move_assign_object<T>(current_idx == requested_idx, source, dest);
269 variant_util_impl<Ts...>::move_assign(current_idx + 1U, requested_idx, source, dest);
270 }
271
272 /// @brief Destroy the input object pointed at @c data if @c current_idx is equal to @c requested_idx.
273 /// @param current_idx the index in @c Ts of the current type
274 /// @param requested_idx the index in @c Ts of the type to be moved
275 /// @param data pointer to the object to destroy
276 static constexpr void destroy(std::size_t current_idx, std::size_t requested_idx, void* data) noexcept {
277 destroy_object<T>(current_idx == requested_idx, data);
278 variant_util_impl<Ts...>::destroy(current_idx + 1U, requested_idx, data);
279 }
280
281 /// @brief Check two objects pointed by @c rhs and @c lhs for equality if @c current_idx is equal to @c requested_idx.
282 /// @param current_idx the index in @c Ts of the current type
283 /// @param requested_idx the index in @c Ts of the type to be moved
284 /// @param lhs pointer to the lhs object
285 /// @param rhs pointer to the rhs object
286 /// @return the result of the comparison
287 static constexpr auto
288 check_equality(std::size_t current_idx, std::size_t requested_idx, void const* lhs, void const* rhs) noexcept
289 -> bool {
290 return check_object_equality<T>(current_idx == requested_idx, lhs, rhs) ||
291 variant_util_impl<Ts...>::check_equality(current_idx + 1U, requested_idx, lhs, rhs);
292 }
293
294 /// @brief Compare two objects pointed by @c rhs and @c lhs for ordering if @c current_idx is equal to @c
295 /// requested_idx.
296 /// @param current_idx the index in @c Ts of the current type
297 /// @param requested_idx the index in @c Ts of the type to be moved
298 /// @param lhs pointer to the lhs object
299 /// @param rhs pointer to the rhs object
300 /// @return the result of the comparison
301 static constexpr auto
302 check_less_than(std::size_t current_idx, std::size_t requested_idx, void const* lhs, void const* rhs) noexcept
303 -> bool {
304 return check_object_less_than<T>(current_idx == requested_idx, lhs, rhs) ||
305 variant_util_impl<Ts...>::check_less_than(current_idx + 1U, requested_idx, lhs, rhs);
306 }
307};
308
309/// @brief Specialization of the end of the recursion. No-op.
310template <>
311class variant_util_impl<> {
312 public:
313 // parasoft-begin-suppress AUTOSAR-M0_1_8-b "The intent of these function are that they do nothing"
314
315 /// @brief Copy construct object at @c to from object at @c from if @c current_idx equals @c idx
316 ///
317 /// This is a no-op for the recursive base specialization.
318 ///
319 static constexpr void
320 copy(std::size_t /*current_idx*/, std::size_t /*idx*/, void const* /*from*/, void* /*to*/) noexcept {}
321
322 /// @brief Copy assign object from @c from to @c to if @c current_idx equals @c idx
323 ///
324 /// This is a no-op for the recursive base specialization.
325 ///
326 static constexpr void
327 copy_assign(std::size_t /*current_idx*/, std::size_t /*idx*/, void const* /*from*/, void* /*to*/) noexcept {}
328 /// @brief Move construct object at @c to from object at @c from if @c current_idx equals @c idx
329 ///
330 /// This is a no-op for the recursive base specialization.
331 ///
332 static constexpr void move(std::size_t /*current_idx*/, std::size_t /*idx*/, void* /*from*/, void* /*to*/) noexcept {}
333
334 /// @brief Move assign object from @c from to @c to if @c current_idx equals @c idx
335 ///
336 /// This is a no-op for the recursive base specialization.
337 ///
338 static constexpr void
339 move_assign(std::size_t /*current_idx*/, std::size_t /*idx*/, void* /*from*/, void* /*to*/) noexcept {}
340
341 /// @brief Destroy object at @c data if @c current_idx equals @c idx
342 ///
343 /// This is a no-op for the recursive base specialization.
344 ///
345 static constexpr void destroy(std::size_t /*current_idx*/, std::size_t /*idx*/, void* /*data*/) noexcept {}
346
347 // parasoft-end-suppress AUTOSAR-M0_1_8-b
348
349 /// @brief Check two objects pointed by @c rhs and @c lhs for equality if @c current_idx is equal to @c requested_idx.
350 /// @param current_idx the index in @c Ts of the current type
351 /// @param requested_idx the index in @c Ts of the type to be moved
352 /// @param lhs pointer to the lhs object
353 /// @param rhs pointer to the rhs object
354 /// @return true if @c requested_idx is representing valueless_by_exception state
355 static constexpr auto check_equality(
356 std::size_t const current_idx, // NOLINT(bugprone-easily-swappable-parameters)
357 std::size_t const requested_idx, // NOLINT(bugprone-easily-swappable-parameters)
358 void const* const lhs,
359 void const* const rhs
360 ) noexcept -> bool {
361 std::ignore = current_idx;
362 std::ignore = lhs;
363 std::ignore = rhs;
364 // two variants in valueless_by_exception state are equal
365 return requested_idx == variant_npos;
366 }
367 /// @brief Compare two objects pointed by @c rhs and @c lhs for ordering if @c current_idx is equal to @c
368 /// @param current_idx the index in @c Ts of the current type
369 /// @param requested_idx the index in @c Ts of the type to be moved
370 /// @param lhs pointer to the lhs object
371 /// @param rhs pointer to the rhs object
372 /// @return always false
373 static constexpr auto check_less_than(
374 std::size_t const current_idx,
375 std::size_t const requested_idx,
376 void const* const lhs,
377 void const* const rhs
378 ) noexcept -> bool {
379 std::ignore = current_idx;
380 std::ignore = requested_idx;
381 std::ignore = lhs;
382 std::ignore = rhs;
383 // two variants in valueless_by_exception state are not ordered
384 return false;
385 }
386};
387
388/// @brief A utility class to recursively destroy/copy/move an object with the correct type base on the index of the
389/// type in the variant.
390/// @note This class should only be used when the type of the object to be constructed is unknown at compile time.
391/// Otherwise, @c construct_at should be used.
392/// @tparam Ts variadic template type argument of the types
393template <typename... Ts>
394class variant_util {
395 public:
396 /// @brief Copy construct the object from @c source to @c dest. Type of the object is @c idx -th from typelist @c Ts
397 /// Placement new is used to copy construct the object.
398 /// @param idx the index in @c Ts of the current type
399 /// @param source pointer to the source object
400 /// @param dest pointer to the destination object
401 inline static void copy(
402 std::size_t idx,
403 void const* source,
404 void* dest
405 ) noexcept(base::all_of_v<std::is_nothrow_copy_constructible<Ts>::value...>) {
406 variant_util_impl<Ts...>::copy(0U, idx, source, dest);
407 }
408
409 /// @brief Copy assign the object from @c source to @c dest. Type of the object is @c idx -th from typelist @c Ts
410 /// @param idx the index in @c Ts of the current type
411 /// @param source pointer to the source object
412 /// @param dest pointer to the destination object
413 inline static void copy_assign(
414 std::size_t idx,
415 void const* source,
416 void* dest
417 ) noexcept(base::all_of_v<std::is_nothrow_copy_assignable<Ts>::value...>) {
418 variant_util_impl<Ts...>::copy_assign(0U, idx, source, dest);
419 }
420
421 /// @brief Move construct the object from @c source to @c dest. Type of the object is @c idx -th from typelist @c Ts
422 /// Placement new is used to move construct the object.
423 /// @param idx the index in @c Ts of the current type
424 /// @param source pointer to the source object
425 /// @param dest pointer to the destination object
426 inline static void move(
427 std::size_t idx,
428 void* source,
429 void* dest
430 ) noexcept(base::all_of_v<std::is_nothrow_move_constructible<Ts>::value...>) {
431 variant_util_impl<Ts...>::move(0U, idx, source, dest);
432 }
433
434 /// @brief Move assign the object from @c source to @c dest. Type of the object is @c idx -th from typelist @c Ts
435 /// @param idx the index in @c Ts of the current type
436 /// @param source pointer to the source object
437 /// @param dest pointer to the destination object
438 inline static void move_assign(
439 std::size_t idx,
440 void* source,
441 void* dest
442 ) noexcept(base::all_of_v<std::is_nothrow_move_assignable<Ts>::value...>) {
443 variant_util_impl<Ts...>::move_assign(0U, idx, source, dest);
444 }
445
446 /// @brief Destroy the input object pointed at @c data. Type of the object is @c idx -th from typelist @c Ts
447 /// @param idx the index in @c Ts of the current type
448 /// @param data pointer to the object to destroy
449 inline static void destroy(std::size_t idx, void* data) noexcept { variant_util_impl<Ts...>::destroy(0U, idx, data); }
450
451 /// @brief Check two objects pointed by @c rhs and @c lhs for equality. Type of the objects is @c idx -th from
452 /// typelist @c Ts
453 /// @param idx the index in @c Ts of the current type
454 /// @param lhs pointer to the lhs object
455 /// @param rhs pointer to the rhs object
456 /// @return true if objects @c lhs and @c rhs are equal or @c idx represents valueless-by-exception state
457 inline static auto check_equality(std::size_t idx, void const* lhs, void const* rhs) noexcept -> bool {
458 return variant_util_impl<Ts...>::check_equality(0U, idx, lhs, rhs);
459 }
460
461 /// @brief Check two objects pointed by @c rhs and @c lhs for less-than ordering. Type of the objects is @c idx -th
462 /// from typelist @c Ts
463 /// @param idx the index in @c Ts of the current type
464 /// @param lhs pointer to the lhs object
465 /// @param rhs pointer to the rhs object
466 /// @return true if object @c lhs is less than @c rhs or false when @c idx represents valueless-by-exception state
467 inline static auto check_less_than(std::size_t idx, void const* lhs, void const* rhs) noexcept -> bool {
468 return variant_util_impl<Ts...>::check_less_than(0U, idx, lhs, rhs);
469 }
470};
471
472/// @brief Forward declaration. Helper to check if a given type can be constructed from the @c I 'th type in a variant.
473/// @tparam Variant the variant type
474/// @tparam I the index of the type to be checked
475template <class Variant, std::size_t I = 0>
476class convertible_checker;
477
478/// @brief Specialization of the empty(end of recursion).
479/// @tparam I always equal to the size of the real variant
480template <std::size_t I>
481class convertible_checker<variant<>, I> {
482 public:
483 /// @brief function used to determine if a type is convertible to a variant alternative
484 ///
485 /// This overload is defined in the recursive base so that all
486 /// convertible_checker specializations declare @c run
487 static void run() = delete;
488};
489
490/// @brief A recursive specialization of the convertible_checker.
491///
492/// This class has two static member functions @c run for each type in the variant. @c accepted_index will use the
493/// overload resolution rule to determine which type of the variant is the best match for the type given in the convert
494/// constructor of the variant. It is a compile error if two or more types in the variant can be converted from the
495/// given type with the same level of match.
496/// @tparam H the head type of the variant
497/// @tparam Ts the tail types of the variant
498/// @tparam I the index of the type to be checked
499template <class H, class... Ts, std::size_t I>
500class convertible_checker<variant<H, Ts...>, I> : convertible_checker<variant<Ts...>, I + 1> {
501 public:
502 using convertible_checker<variant<Ts...>, I + 1>::run;
503
504 // parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
505 /// @brief undefined function used to determine if a type is convertible to a variant alternative
506 /// @return integral constant containing the alternative index
507 static auto run(H const&, std::integral_constant<std::size_t, I>) -> std::integral_constant<std::size_t, I>;
508 // parasoft-end-suppress CERT_C-EXP37-a-3
509
510 // parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
511 /// @brief undefined function used to determine if a type is convertible to a variant alternative
512 /// @return integral constant containing the alternative index
513 static auto run(H&&, std::integral_constant<std::size_t, I>) -> std::integral_constant<std::size_t, I>;
514 // parasoft-end-suppress CERT_C-EXP37-a-3
515};
516
517/// @brief Helper to determine which type in the variant can be constructed from the given type.
518/// @tparam Variant the variant type
519/// @tparam T the type to be checked
520template <class Variant, class T, class = void>
521class accepted_index {};
522
523/// @brief Implementation of @c accepted_index .
524/// @tparam Variant the variant type
525/// @tparam T the type to be checked
526template <class Variant, class T>
527class accepted_index<Variant, T, void_t<decltype(convertible_checker<Variant>::run(std::declval<T>(), {}))>>
528 : public decltype(convertible_checker<Variant>::run(std::declval<T>(), {})) {};
529
530} // namespace variant_detail
531
532// parasoft-begin-suppress AUTOSAR-A12_0_1-a "False Positive: Copy constructor is defined or deleted as appropriate"
533// parasoft-begin-suppress AUTOSAR-A12_1_5-a "Delegating constructors would not reduce duplication"
534/// @brief a backport of C++17's @c std::variant
535/// @tparam Ts The set of alternatives that can be held by the variant.
536template <typename... Ts>
537// Justification: False positive about copy constructor not generated
538// NOLINTNEXTLINE(hicpp-special-member-functions)
540 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'util_type' does not hide another identifier"
541 /// @brief Alias to a utility class for this variant type.
542 using util_type = variant_detail::variant_util<Ts...>;
543 // parasoft-end-suppress AUTOSAR-A2_10_1-e
544
545 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'nth_type' does not hide another identifier"
546 /// @brief Obtains the alternative type for a given index
547 /// @tparam Index alternative type index
548 template <std::size_t Index>
549 using nth_type = type_lists::at_t<type_list<Ts...>, Index>;
550 // parasoft-end-suppress AUTOSAR-A2_10_1-e
551
552 static_assert(sizeof...(Ts) > 0, "Empty variant is not allowed");
553 static_assert(base::all_of_v<!std::is_reference<Ts>::value...>, "variant must have no reference alternative");
554
555 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'num_types' does not hide another identifier"
556 /// @brief Number of alternative types
557 static constexpr std::size_t num_types{sizeof...(Ts)};
558 // parasoft-end-suppress AUTOSAR-A2_10_1-e
559
560 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'max_size' does not hide another identifier"
561 /// @brief The maximum size of the alternative types
562 static constexpr std::size_t max_size{std::max({sizeof(Ts)...})};
563 // parasoft-end-suppress AUTOSAR-A2_10_1-e
564
565 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'max_align' does not hide another identifier"
566 /// @brief The maximum alignment of the alternative types
567 static constexpr std::size_t max_align{std::max({alignof(Ts)...})};
568 // parasoft-end-suppress AUTOSAR-A2_10_1-e
569
570 /// @brief The type of the argument to the "copy assignment operator".
571 ///
572 /// Either @c variant to provide a copy assignment when all the alternative types are copy constructible and copy
573 /// assignable, or @c non_constructible_dummy otherwise.
574 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'copy_assignment_arg' does not hide another identifier"
577 variant,
579 // parasoft-end-suppress AUTOSAR-A2_10_1-e
580
581 /// @brief the type of the argument to the "copy assignment operator". The opposite to @c copy_assignment_arg .
582 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'dummy_copy_assign_source' does not hide another
583 // identifier"
587 variant>;
588 // parasoft-end-suppress AUTOSAR-A2_10_1-e
589
590 /// @brief The type of the argument to the "copy constructor".
591 ///
592 /// Either @c variant to provide a copy ctor when all the alternative types are copy constructible, or
593 /// @c non_constructible_dummy otherwise.
594 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'copy_ctor_arg' does not hide another identifier"
595 using copy_ctor_arg =
597 // parasoft-end-suppress AUTOSAR-A2_10_1-e
598
599 /// @brief The type of the argument to the "copy constructor". The opposite to @c copy_ctor_arg.
600 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'dummy_copy_ctor_source' does not hide another
601 // identifier"
604 // parasoft-end-suppress AUTOSAR-A2_10_1-e
605
606 /// @brief The type of the argument to the "move assignment operator".
607 ///
608 /// Either @c variant to provide a move assignment when all the alternative types are move constructible and move
609 /// assignable, or @c non_constructible_dummy otherwise.
610 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'move_assignment_arg' does not hide another identifier"
613 variant,
615 // parasoft-end-suppress AUTOSAR-A2_10_1-e
616
617 /// @brief The type of the argument to the "move assignment operator". The opposite to @c move_assignment_arg.
618 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'dummy_move_assign_source' does not hide another
619 // identifier"
623 variant>;
624 // parasoft-end-suppress AUTOSAR-A2_10_1-e
625
626 /// @brief The type of the argument to the "move constructor".
627 ///
628 /// Either @c variant to provide a move ctor when all the alternative types are move constructible, or
629 /// @c non_constructible_dummy otherwise.
630 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'move_ctor_arg' does not hide another identifier"
631 using move_ctor_arg =
633 // parasoft-end-suppress AUTOSAR-A2_10_1-e
634
635 /// @brief The type of the argument to the "move constructor". The opposite to @c move_ctor_arg.
636 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'dummy_move_ctor_source' does not hide another
637 // identifier"
640 // parasoft-end-suppress AUTOSAR-A2_10_1-e
641
642 public:
643 /// @brief Default constructor, which initializes the variant to a default constructed instance of its 0'th
644 /// alternative.
645 ///
646 /// @pre Only participates in overload resolution if the first type in @c Ts is default constructible.
647 template <
648 typename T0 = nth_type<0>,
652 idx_{} {
653 // Justification: It's intended to use reinterpret_cast to construct
654 // the object on an uninitialized address.
655 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
656 construct_at(reinterpret_cast<T0*>(data_.data()));
657 }
658
659 /// @brief Copy Constructor from another variant of the same alternative types.
660 ///
661 /// If the other variant is valueless, this variant will also be valueless.
662 /// @pre Only participates in overload resolution if every type in @c Ts is copy constructible.
663 /// @param other the other variant to copy from
664 // parasoft-begin-suppress AUTOSAR-A13_3_1-a "False positive: No forwarding reference"
665 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
668 idx_{other.idx_} {
669 // util_type::copy is no-op for valueless-by-exception
671 }
672 // parasoft-end-suppress AUTOSAR-A13_3_1-a
673
674 /// @brief Copy Constructor from another variant of the same alternative types.
675 ///
676 /// If the other variant is valueless, this variant will also be valueless.
677 /// @pre Only participates in overload resolution if every type in @c Ts is copy constructible.
678 /// @param other the other variant to copy from
680
681 // parasoft-begin-suppress AUTOSAR-A15_5_1-b-2 "False positive: Conditionally noxecept"
682 // parasoft-begin-suppress AUTOSAR-A8_4_6-a-2 "False positive: The data is moved via the 'util_type::move' function"
683 // parasoft-begin-suppress AUTOSAR-A8_4_5-a-2 "False positive: The data is moved via the 'util_type::move' function"
684 // parasoft-begin-suppress AUTOSAR-A12_8_4-a-2 "False positive: The data is moved via the 'util_type::move' function"
685 /// @brief Move Constructor from another variant.
686 ///
687 /// If the other variant is valueless, this variant will also be valueless.
688 /// @pre Only participates in overload resolution if every type in @c Ts is move constructible.
689 /// @param other the other variant to move from
690 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
691 variant(move_ctor_arg&& other) noexcept(base::all_of_v<std::is_nothrow_move_constructible<Ts>::value...>)
693 idx_{other.idx_} {
694 // util_type::move is no-op for valueless-by-exception
695 util_type::move(other.idx_, other.data_.data(), data_.data());
696 }
697 // parasoft-env-suppress AUTOSAR-A12_8_4-a-2
698 // parasoft-env-suppress AUTOSAR-A8_4_5-a-2
699 // parasoft-env-suppress AUTOSAR-A8_4_6-a-2
700 // parasoft-env-suppress AUTOSAR-A15_5_1-b-2
701
702 /// @brief Move Constructor form another variant.
703 ///
704 /// If the other variant is valueless, this variant will also be valueless.
705 /// @pre Only participates in overload resolution if every type in @c Ts is move constructible.
706 /// @param other the other variant to move from
707 variant(dummy_move_ctor_source&& other) = delete;
708
709 // parasoft-begin-suppress AUTOSAR-A2_7_2-a-2 "False positive: no commented-out code"
710 /// @brief Constructor that initializes this variant from one of its alternative types.
711 ///
712 /// This constructor will pick the constructor overload of the alternative type @c Tj that <c> T_i x[] = {
713 /// std::forward<T>(value) }; </c> is valid. If more than one alternative type satisfies this condition, the
714 /// compilation will fail.
715 /// @tparam T the type to construct this variant
716 /// @tparam I the deduced index of the alternative type that T can construct
717 /// @tparam Tj the deduced alternative type that T can construct
718 /// @param value the object to forward into the variant
719 // parasoft-end-suppress AUTOSAR-A2_7_2-a-2
720 template <
721 typename T,
723 typename Tj = nth_type<I>,
725 std::enable_if_t<!std::is_same<typename std::decay<T>::type, variant>::value>,
726 std::enable_if_t<std::is_constructible<Tj, T>::value>> = nullptr>
727 // Justification: The forwarding reference constructor won't hide copy/move
728 // constructor since the constraints ensures T cannot be another variant.
729 // Justification: std::variant doesn't require this to be explicit.
730 // NOLINTNEXTLINE(bugprone-forwarding-reference-overload,google-explicit-constructor,hicpp-explicit-conversions)
733 idx_(I) {
734 // Justification: It's intended to use reinterpret_cast to construct
735 // the object on an uninitialized address.
736 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
737 construct_at(reinterpret_cast<Tj*>(data_.data()), std::forward<T>(value));
738 }
739
740 /// @brief Copy Assignment operator from another variant of the same alternative types.
741 ///
742 /// If the other type is valueless, or exception is thrown during copying, this variant will also be valueless.
743 /// @pre Only participates in overload resolution if every type in @c Ts is copy-assignable.
744 /// @param rhs the other variant to copy from
747 -> variant& {
748 if (this != &rhs) {
749 if (index() != rhs.index()) { // different
750 destroy();
751 util_type::copy(rhs.idx_, rhs.data_.data(), data_.data()); // no-op for valueless-by-exception
752 idx_ = rhs.idx_;
753 } else {
754 util_type::copy_assign(rhs.idx_, rhs.data_.data(), data_.data()); // no-op for valueless-by-exception
755 }
756 }
757
758 return *this;
759 }
760 /// @brief Copy Assignment operator from another variant of the same alternative types.
761 ///
762 /// If the other type is valueless, or exception is thrown during copying, this variant will also be valueless.
763 /// @pre Only participates in overload resolution if every type in @c Ts is copy-assignable.
764 /// @param rhs the other variant to copy from
765 auto operator=(dummy_copy_assign_source const& rhs) -> variant& = delete;
766
767 // parasoft-begin-suppress AUTOSAR-A15_5_1-b-2 "False positive: Conditionally noxecept"
768 // parasoft-begin-suppress AUTOSAR-A8_4_6-a-2 "False positive: The data is moved via the 'util_type::move*' function"
769 // parasoft-begin-suppress AUTOSAR-A8_4_5-a-2 "False positive: The data is moved via the 'util_type::move*' function"
770 // parasoft-begin-suppress AUTOSAR-A12_8_4-a-2 "False positive: The data is moved via the 'util_type::move*' function"
771 /// @brief Move Assignment operator from another variant of the same alternative types.
772 ///
773 /// If the other type is valueless, this variant will also be valueless.
774 /// @pre Only participates in overload resolution if every type in @c Ts is move-assignable.
775 /// @param rhs the other variant to move from
776 auto operator=(move_assignment_arg&& rhs
778 -> variant& {
779 if (this != &rhs) {
780 if (index() != rhs.index()) {
781 destroy();
782 util_type::move(rhs.idx_, rhs.data_.data(), data_.data()); // no-op for valueless-by-exception
783 idx_ = rhs.idx_;
784 } else {
785 util_type::move_assign(rhs.idx_, rhs.data_.data(), data_.data()); // no-op for valueless-by-exception
786 }
787 }
788
789 return *this;
790 }
791
792 // parasoft-end-suppress AUTOSAR-A12_8_4-a-2
793 // parasoft-end-suppress AUTOSAR-A8_4_5-a-2
794 // parasoft-end-suppress AUTOSAR-A8_4_6-a-2
795 // parasoft-end-suppress AUTOSAR-A15_5_1-b-2
796
797 /// @brief Move Assignment operator from another variant of the same alternative types.
798 ///
799 /// If the other type is valueless, this variant will also be valueless.
800 /// @pre Only participates in overload resolution if every type in @c Ts is move-assignable.
801 /// @param rhs the other variant to move from
802 auto operator=(dummy_move_assign_source&& rhs) -> variant& = delete;
803
804 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "False positive: comparison operators are permitted"
805 // parasoft-begin-suppress AUTOSAR-A0_1_3-a-2 "False positive: Function is namespace scope and used in other
806 // translation units"
807 /// @brief Equality comparison
808 /// @pre The behavior is undefined if not all the alternatives support equality comparison.
809 /// @param lhs variant to compare
810 /// @param rhs the other variant to compare
811 /// @return true if both variants are valueless, or both variants hold the same alternative type and the value of that
812 /// alternative type is equal.
813 /// @return false otherwise.
814 friend auto operator==(variant const& lhs, variant const& rhs) noexcept -> bool {
815 if (lhs.index() != rhs.index()) {
816 return false;
817 }
818
819 // util_type::check_equality returns true for valueless-by-exception state
820 return util_type::check_equality(
821 lhs.idx_,
822 static_cast<void const*>(lhs.data_.data()),
823 static_cast<void const*>(rhs.data_.data())
824 );
825 }
826 // parasoft-end-suppress AUTOSAR-A0_1_3-a-2
827 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
828
829 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "False positive: comparison operators are permitted"
830 // parasoft-begin-suppress AUTOSAR-A0_1_3-a-2 "False positive: Function is namespace scope and used in other
831 // translation units"
832 /// @brief Less-than comparison
833 /// @pre The behavior is undefined if not all the alternatives support less than comparison.
834 /// @param lhs variant to compare
835 /// @param rhs the other variant to compare
836 /// @return false if either variant is valueless
837 /// @return Otherwise, returns the result of invoking @c std::less on the held alternatives of the two variants.
838 friend auto operator<(variant const& lhs, variant const& rhs) noexcept -> bool {
839 if (lhs.index() != rhs.index()) {
840 return (lhs.index() + 1U) < (rhs.index() + 1U);
841 }
842
843 // util_type::check_less_than returns false for valueless-by-exception state
844 return util_type::check_less_than(
845 lhs.idx_,
846 static_cast<void const*>(lhs.data_.data()),
847 static_cast<void const*>(rhs.data_.data())
848 );
849 }
850 // parasoft-end-suppress AUTOSAR-A0_1_3-a-2
851 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
852
853 /// @brief Get the index of the alternative type that this variant currently holds.
854 /// @return std::size_t the index of the alternative type that this variant currently holds, or @c variant_npos if the
855 /// variant is valueless.
856 auto index() const noexcept -> std::size_t { return idx_; }
857
858 /// @brief Emplaces a value into the variant by index.
859 /// @tparam I the index of the alternative type to emplace
860 /// @tparam Args the variadic argument type to pass into the constructor of
861 /// the alternative type
862 /// @param args Arguments to be forwarded to the constructor of the emplaced type.
863 /// @return A reference to the emplaced object.
864 /// @post If the variant was not valueless, the currently held value is destroyed
865 /// @post The variant will hold the value the returned reference points to.
866 /// @post @c holds_alternative<I>(*this) will return true
867 /// @post index() will return @c I
868 template <std::size_t I, typename... Args>
869 auto emplace(Args&&... args) noexcept(std::is_nothrow_constructible<nth_type<I>, Args...>::value) -> nth_type<I>& {
870 destroy();
871 using selected_type = nth_type<I>;
872 // Justification: It's intended to use reinterpret_cast to construct
873 // the object on an uninitialized address.
874 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
875 construct_at(reinterpret_cast<selected_type*>(data_.data()), std::forward<Args>(args)...);
876 idx_ = I;
877 return get<I>();
878 }
879
880 /// @brief Emplaces a value into the variant by index.
881 /// @tparam I the index of the alternative type to emplace
882 /// @tparam Args the variadic argument type to pass into the constructor of
883 /// the alternative type
884 /// @param init An initializer list to forward to the constructor of the emplaced type.
885 /// @param args Arguments to be forwarded to the constructor of the emplaced type.
886 /// @return A reference to the emplaced object.
887 /// @post If the variant was not valueless, the currently held value is destroyed
888 /// @post The variant will hold the value the returned reference points to.
889 /// @post @c holds_alternative<I>(*this) will return true
890 /// @post index() will return @c I
891 template <std::size_t I, typename U, typename... Args>
892 auto emplace(std::initializer_list<U> init, Args&&... args) noexcept(
894 ) -> nth_type<I>& {
895 destroy();
896 using selected_type = nth_type<I>;
897 // Justification: It's intended to use reinterpret_cast to construct
898 // the object on an uninitialized address.
899 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
900 construct_at(reinterpret_cast<selected_type*>(data_.data()), init, std::forward<Args>(args)...);
901 idx_ = I;
902 return get<I>();
903 }
904
905 /// @brief Emplaces a value into the variant by type.
906 /// @tparam T the alternative type to emplace
907 /// @param args Arguments to be forwarded to the constructor of the emplaced type.
908 /// @return A reference to the emplaced object.
909 /// @post If the variant was not valueless, the currently held value is destroyed
910 /// @post The variant will hold the value the returned reference points to.
911 /// @post @c holds_alternative<T>(*this) will return true
912 /// @post index() will return the the equivalent of <c> index_of_v<T, Ts...> </c>
913 template <typename T, typename... Args>
914 auto emplace(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> T& {
915 destroy();
916 // Justification: It's intended to use reinterpret_cast to construct
917 // the object on an uninitialized address.
918 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
919 construct_at(reinterpret_cast<T*>(data_.data()), std::forward<Args>(args)...);
920 idx_ = base::index_of_v<T, Ts...>;
921 return get<T>();
922 }
923
924 /// @brief Emplaces a value into the variant by type.
925 /// @tparam T the alternative type to emplace
926 /// @param init An initializer list to forward to the constructor of the emplaced type.
927 /// @param args Arguments to be forwarded to the constructor of the emplaced type.
928 /// @return A reference to the emplaced object.
929 /// @post If the variant was not valueless, the currently held value is destroyed
930 /// @post The variant will hold the value the returned reference points to.
931 /// @post @c holds_alternative<T>(*this) will return true
932 /// @post index() will return the the equivalent of <c> index_of_v<T, Ts...> </c>
933 template <typename T, typename U, typename... Args>
934 auto emplace(std::initializer_list<U> init, Args&&... args) noexcept(
936 ) -> T& {
937 destroy();
938 // Justification: It's intended to use reinterpret_cast to construct
939 // the object on an uninitialized address.
940 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
941 construct_at(reinterpret_cast<T*>(data_.data()), init, std::forward<Args>(args)...);
942 idx_ = base::index_of_v<T, Ts...>;
943 return get<T>();
944 }
945
946 /// @brief Get by type.
947 /// @tparam T the alternative type to get
948 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
949 /// by the variant does not match the type requested.
950 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
951 /// match the type requested else @c ARENE_PRECONDITION violation.
952 /// @return T& The reference to the held object.
953 template <typename T>
954 auto get() & noexcept(!detail::are_exceptions_enabled_v) -> T& {
955 return get<base::index_of_v<T, Ts...>>();
956 }
957 /// @brief Get by type.
958 /// @tparam T the alternative type to get
959 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
960 /// by the variant does not match the type requested.
961 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
962 /// match the type requested else @c ARENE_PRECONDITION violation.
963 /// @return T const& The reference to the held object.
964 template <typename T>
965 auto get() const& noexcept(!detail::are_exceptions_enabled_v) -> T const& {
966 return get<base::index_of_v<T, Ts...>>();
967 }
968
969 /// @brief Get by type.
970 /// @tparam T the alternative type to get
971 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
972 /// by the variant does not match the type requested.
973 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
974 /// match the type requested else @c ARENE_PRECONDITION violation.
975 /// @return T&& The reference to the held object.
976 template <typename T>
977 auto get() && noexcept(!detail::are_exceptions_enabled_v) -> T&& {
978 return std::move(get<base::index_of_v<T, Ts...>>());
979 }
980 /// @brief Get by type.
981 /// @tparam T the alternative type to get
982 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
983 /// by the variant does not match the type requested.
984 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
985 /// match the type requested else @c ARENE_PRECONDITION violation.
986 /// @return T const&& The reference to the held object.
987 template <typename T>
988 auto get() const&& noexcept(!detail::are_exceptions_enabled_v) -> T const&& {
989 // parasoft-begin-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
990 return std::move(get<base::index_of_v<T, Ts...>>());
991 // parasoft-end-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
992 }
993
994 /// @brief Get the object stored in this variant by the index
995 /// @tparam Index the index into @c Ts of the alternative to get
996 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object
997 /// currently held by the variant does not match the index requested.
998 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
999 /// match the type requested else @c ARENE_PRECONDITION violation.
1000 /// @return nth_type<Index>& The reference to the held object.
1001 template <std::size_t Index>
1003 return get_impl<Index, nth_type<Index>&>(*this);
1004 }
1005
1006 /// @brief Get the object stored in this variant by the index
1007 /// @tparam Index the index into @c Ts of the alternative to get
1008 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object
1009 /// currently held by the variant does not match the index requested.
1010 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1011 /// match the type requested else @c ARENE_PRECONDITION violation.
1012 /// @return nth_type<Index> const& The reference to the held object.
1013 template <std::size_t Index>
1014 auto get() const& noexcept(!detail::are_exceptions_enabled_v) -> nth_type<Index> const& {
1015 return get_impl<Index, nth_type<Index> const&>(*this);
1016 }
1017
1018 /// @brief Get the object stored in this variant by the index
1019 /// @tparam Index the index into @c Ts of the alternative to get
1020 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object
1021 /// currently held by the variant does not match the index requested.
1022 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1023 /// match the type requested else @c ARENE_PRECONDITION violation.
1024 /// @return nth_type<Index>&& The reference to the held object.
1025 template <std::size_t Index>
1026 auto get() && noexcept(!detail::are_exceptions_enabled_v) -> nth_type<Index>&& {
1027 return get_impl<Index, nth_type<Index>&&>(std::move(*this));
1028 }
1029
1030 /// @brief Get the object stored in this variant by the index
1031 /// @tparam Index the index into @c Ts of the alternative to get
1032 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object
1033 /// currently held by the variant does not match the index requested.
1034 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1035 /// match the type requested else @c ARENE_PRECONDITION violation.
1036 /// @return nth_type<Index> const&& The reference to the held object.
1037 template <std::size_t Index>
1038 auto get() const&& noexcept(!detail::are_exceptions_enabled_v) -> nth_type<Index> const&& {
1039 // parasoft-begin-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1040 return get_impl<Index, nth_type<Index> const&&>(std::move(*this));
1041 // parasoft-end-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1042 }
1043
1044 /// @brief Check if the variant is valueless.
1045 ///
1046 /// A variant becomes valueless if and only if an exception is thrown during copy or move initialization
1047 /// @return true if the variant does not hold a value
1048 /// @return false if the variant holds a value.
1049 constexpr auto valueless_by_exception() const noexcept -> bool { return idx_ == variant_npos; }
1050
1051 /// @brief Calls the destructor of the alternative type.
1052 ~variant() { destroy(); }
1053
1054 private:
1055 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'get_impl' does not hide another identifier"
1056 /// @brief Get the object stored in this variant by the index
1057 /// @tparam Index the index into @c Ts of the alternative to get
1058 /// @tparam Alternative (const-qualified) alternative type for Index
1059 /// @tparam Self (const-qualified) variant type
1060 /// @param self reference to (const-qualified) variant type
1061 /// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object
1062 /// currently held by the variant does not match the index requested.
1063 /// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1064 /// match the type index requested else @c ARENE_PRECONDITION violation.
1065 /// @return The reference to the held object.
1066 template <std::size_t Index, typename AlternativeRefT, typename Self>
1067 static auto get_impl(Self&& self) noexcept(!detail::are_exceptions_enabled_v) -> AlternativeRefT {
1068 variant_detail::variant_must_have_value(Index, self.idx_);
1069 ARENE_IGNORE_START();
1070 ARENE_IGNORE_ALL(
1071 "-Wstrict-aliasing",
1072 "It's safe to use reinterpret_cast here since the check above ensures that the type of the object "
1073 "currently held by the variant is the same as the type requested."
1074 );
1075 return ::arene::base::forward_like<Self>(
1076 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1077 *reinterpret_cast<std::remove_reference_t<AlternativeRefT>*>(std::forward<Self>(self).data_.data())
1078 );
1079 ARENE_IGNORE_END();
1080 }
1081 // parasoft-end-suppress AUTOSAR-A2_10_1-e
1082
1083 /// @brief Destroy the object held by this variant if it's not valueless.
1084 void destroy() noexcept {
1085 // util_type::destroy is no-op for valueless-by-exception
1086 util_type::destroy(idx_, data_.data());
1087 idx_ = variant_npos;
1088 }
1089
1090 /// @brief index of the active alternative
1091 std::size_t idx_{variant_npos};
1092 /// @brief actual type and data storage
1093 alignas(max_align) array<byte, max_size> data_{};
1094};
1095// parasoft-end-suppress AUTOSAR-A12_1_5-a
1096// parasoft-end-suppress AUTOSAR-A12_0_1-a
1097
1098/// @brief Get value held by a variant by type.
1099/// @tparam T the alternative type to get
1100/// @param var variant to get from
1101/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
1102/// by the variant does not match the type requested.
1103/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
1104/// match the type requested else @c ARENE_PRECONDITION violation.
1105/// @return The reference to the held object.
1106template <typename T, typename... Ts>
1107inline constexpr auto get(variant<Ts...>& var) noexcept(!detail::are_exceptions_enabled_v) -> T& {
1108 static_assert(!std::is_void<T>::value, "T should not be void");
1109 return var.template get<T>();
1110}
1111
1112/// @brief Get value held by a variant by type.
1113/// @tparam T the alternative type to get
1114/// @param var variant to get from
1115/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
1116/// by the variant does not match the type requested.
1117/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
1118/// match the type requested else @c ARENE_PRECONDITION violation.
1119/// @return The reference to the held object.
1120template <typename T, typename... Ts>
1121inline constexpr auto get(variant<Ts...> const& var) noexcept(!detail::are_exceptions_enabled_v) -> T const& {
1122 static_assert(!std::is_void<T>::value, "T should not be void");
1123 return var.template get<T>();
1124}
1125
1126/// @brief Get value held by a variant by type.
1127/// @tparam T the alternative type to get
1128/// @param var variant to get from
1129/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
1130/// by the variant does not match the type requested.
1131/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
1132/// match the type requested else @c ARENE_PRECONDITION violation.
1133/// @return The reference to the held object.
1134template <typename T, typename... Ts>
1135inline constexpr auto get(variant<Ts...>&& var) noexcept(!detail::are_exceptions_enabled_v) -> T&& {
1136 static_assert(!std::is_void<T>::value, "T should not be void");
1137 return std::move(var).template get<T>();
1138}
1139
1140/// @brief Get value held by a variant by type.
1141/// @tparam T the alternative type to get
1142/// @param var variant to get from
1143/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type of the object currently held
1144/// by the variant does not match the type requested.
1145/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type of the object currently held by the variant must
1146/// match the type requested else @c ARENE_PRECONDITION violation.
1147/// @return The reference to the held object.
1148template <typename T, typename... Ts>
1149inline constexpr auto get(variant<Ts...> const&& var) noexcept(!detail::are_exceptions_enabled_v) -> T const&& {
1150 static_assert(!std::is_void<T>::value, "T should not be void");
1151 // parasoft-begin-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1152 return std::move(var).template get<T>();
1153 // parasoft-end-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1154}
1155
1156/// @brief Get value held by a variant by index.
1157/// @tparam Index the index into @c Ts of the alternative to get
1158/// @param var variant to get from
1159/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object currently
1160/// held by the variant does not match the index requested.
1161/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1162/// match the type requested else @c ARENE_PRECONDITION violation.
1163/// @return The reference to the held object.
1164// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1165template <std::size_t I, typename... Ts>
1166constexpr auto get(variant<Ts...>& var) noexcept(!detail::are_exceptions_enabled_v)
1167 -> variant_alternative_t<I, variant<Ts...>>& {
1168 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1169 return var.template get<I>();
1170}
1171// parasoft-end-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1172/// @brief Get value held by a variant by index.
1173/// @tparam Index the index into @c Ts of the alternative to get
1174/// @param var variant to get from
1175/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object currently
1176/// held by the variant does not match the index requested.
1177/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1178/// match the type requested else @c ARENE_PRECONDITION violation.
1179/// @return The reference to the held object.
1180// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1181template <std::size_t I, typename... Ts>
1182constexpr auto get(variant<Ts...> const& var) noexcept(!detail::are_exceptions_enabled_v)
1183 -> variant_alternative_t<I, variant<Ts...>> const& {
1184 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1185 return var.template get<I>();
1186}
1187// parasoft-end-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1188
1189/// @brief Get value held by a variant by index.
1190/// @tparam Index the index into @c Ts of the alternative to get
1191/// @param var variant to get from
1192/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object currently
1193/// held by the variant does not match the index requested.
1194/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the index type of the object currently held by the variant must
1195/// match the type requested else @c ARENE_PRECONDITION violation.
1196/// @return The reference to the held object.
1197// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1198template <std::size_t I, typename... Ts>
1199constexpr auto get(variant<Ts...>&& var) noexcept(!detail::are_exceptions_enabled_v)
1200 -> variant_alternative_t<I, variant<Ts...>>&& {
1201 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1202 return std::move(var).template get<I>();
1203}
1204// parasoft-end-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1205/// @brief Get value held by a variant by index.
1206/// @tparam Index the index into @c Ts of the alternative to get
1207/// @param var variant to get from
1208/// @throw bad_variant_access if @c ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) and if the type index of the object currently
1209/// held by the variant does not match the index requested.
1210/// @pre If @c ARENE_IS_OFF(ARENE_EXCEPTIONS_ENABLED) the type index of the object currently held by the variant must
1211/// match the type requested else @c ARENE_PRECONDITION violation.
1212/// @return The reference to the held object.
1213// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1214template <std::size_t I, typename... Ts>
1215constexpr auto get(variant<Ts...> const&& var) noexcept(!detail::are_exceptions_enabled_v)
1216 -> variant_alternative_t<I, variant<Ts...>> const&& {
1217 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1218 // parasoft-begin-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1219 return std::move(var).template get<I>();
1220 // parasoft-end-suppress AUTOSAR-A18_9_3-a "Must maintain the reference type of the return value"
1221}
1222// parasoft-end-suppress AUTOSAR-M3_3_2-a "False positive, this is not a member function and thus cannot be static."
1223
1224// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
1225/// @brief Check if the variant holds a value of a given alternative type.
1226/// @tparam T the alternative type to check
1227/// @tparam Ts the types that the variant can hold
1228/// @param var the variant to check
1229/// @return true if and only if the variant holds a value of type T.
1230/// @return false otherwise.
1231/// @pre Ill-formed if @c T does not appear exactly once in @c Ts .
1232template <class T, class... Ts>
1233constexpr auto holds_alternative(variant<Ts...> const& var) noexcept -> bool {
1234 return var.index() == base::index_of_v<T, Ts...>;
1235}
1236// parasoft-end-suppress AUTOSAR-M3_3_2-a
1237
1238/// @brief Attempt to get a pointer to the object held by the variant by index.
1239/// @tparam I Index of the type in @c Ts to get
1240/// @tparam Ts the types that the variant can hold
1241/// @param ptr A pointer to the variant to access
1242/// @return A pointer to the held object if the variant holds a value of the type, else @c nullptr .
1243template <std::size_t I, typename... Ts>
1244inline constexpr auto get_if(variant<Ts...>* ptr) noexcept
1246 using type = variant_alternative_t<I, variant<Ts...>>;
1247 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1248 static_assert(!std::is_void<type>::value, "T should not be void");
1249 if ((ptr != nullptr) && (ptr->index() == I)) {
1250 return std::addressof(ptr->template get<I>());
1251 }
1252 return nullptr;
1253}
1254
1255/// @brief Attempt to get a pointer to the object held by the variant by index.
1256/// @tparam I Index of the type in @c Ts to get
1257/// @tparam Ts the types that the variant can hold
1258/// @param ptr A pointer to the variant to access
1259/// @return A pointer to the held object if the variant holds a value of the type, else @c nullptr .
1260template <std::size_t I, typename... Ts>
1261inline constexpr auto get_if(variant<Ts...> const* ptr) noexcept
1263 using type = variant_alternative_t<I, variant<Ts...>>;
1264 static_assert(I < sizeof...(Ts), "The index should be in [0, number of alternatives)");
1265 static_assert(!std::is_void<type>::value, "T should not be void");
1266 if ((ptr != nullptr) && (ptr->index() == I)) {
1267 return std::addressof(ptr->template get<I>());
1268 }
1269 return nullptr;
1270}
1271
1272/// @brief Attempt to get a pointer to the object held by the variant by type.
1273/// @tparam T Type in @c Ts to get
1274/// @tparam Ts the types that the variant can hold
1275/// @param ptr A pointer to the variant to access
1276/// @return A pointer to the held object if the variant holds a value of the type, else @c nullptr .
1277template <typename T, typename... Ts>
1278inline constexpr auto get_if(variant<Ts...>* ptr) noexcept -> std::add_pointer_t<T> {
1279 static_assert(!std::is_void<T>::value, "T should not be void");
1280 return get_if<base::index_of_v<T, Ts...>>(ptr);
1281}
1282/// @brief Attempt to get a pointer to the object held by the variant by type.
1283/// @tparam T Type in @c Ts to get
1284/// @tparam Ts the types that the variant can hold
1285/// @param ptr A pointer to the variant to access
1286/// @return A pointer to the held object if the variant holds a value of the type, else @c nullptr .
1287template <typename T, typename... Ts>
1288inline constexpr auto get_if(variant<Ts...> const* ptr) noexcept -> std::add_pointer_t<T const> {
1289 static_assert(!std::is_void<T>::value, "T should not be void");
1290 return get_if<base::index_of_v<T, Ts...>>(ptr);
1291}
1292
1293} // namespace base
1294} // namespace arene
1295
1296#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_VARIANT_VARIANT_HPP_
~variant()
Calls the destructor of the alternative type.
Definition variant.hpp:1052
auto get() const &&noexcept(!detail::are_exceptions_enabled_v) -> T const &&
Get by type.
Definition variant.hpp:988
constexpr auto valueless_by_exception() const noexcept -> bool
Check if the variant is valueless.
Definition variant.hpp:1049
auto get() &&noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > &&
Get the object stored in this variant by the index.
Definition variant.hpp:1026
variant() noexcept(std::is_nothrow_default_constructible< T0 >::value)
Default constructor, which initializes the variant to a default constructed instance of its 0'th alte...
Definition variant.hpp:650
auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible< nth_type< I >, Args... >::value) -> nth_type< I > &
Emplaces a value into the variant by index.
Definition variant.hpp:869
auto get() const &&noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > const &&
Get the object stored in this variant by the index.
Definition variant.hpp:1038
variant(move_ctor_arg &&other) noexcept(base::all_of_v< std::is_nothrow_move_constructible< Ts >::value... >)
Move Constructor from another variant.
Definition variant.hpp:691
auto get() &&noexcept(!detail::are_exceptions_enabled_v) -> T &&
Get by type.
Definition variant.hpp:977
auto emplace(std::initializer_list< U > init, Args &&... args) noexcept(std::is_nothrow_constructible< T, std::initializer_list< U >, Args... >::value) -> T &
Emplaces a value into the variant by type.
Definition variant.hpp:934
auto get() &noexcept(!detail::are_exceptions_enabled_v) -> T &
Get by type.
Definition variant.hpp:954
auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) -> T &
Emplaces a value into the variant by type.
Definition variant.hpp:914
friend auto operator<(variant const &lhs, variant const &rhs) noexcept -> bool
Less-than comparison.
Definition variant.hpp:838
auto emplace(std::initializer_list< U > init, Args &&... args) noexcept(std::is_nothrow_constructible< nth_type< I >, std::initializer_list< U >, Args... >::value) -> nth_type< I > &
Emplaces a value into the variant by index.
Definition variant.hpp:892
friend auto operator==(variant const &lhs, variant const &rhs) noexcept -> bool
Equality comparison.
Definition variant.hpp:814
auto get() &noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > &
Get the object stored in this variant by the index.
Definition variant.hpp:1002
auto get() const &noexcept(!detail::are_exceptions_enabled_v) -> nth_type< Index > const &
Get the object stored in this variant by the index.
Definition variant.hpp:1014
auto operator=(move_assignment_arg &&rhs) noexcept(base::all_of_v< std::is_nothrow_move_constructible< Ts >::value... > &&base::all_of_v< std::is_nothrow_move_assignable< Ts >::value... >) -> variant &
Move Assignment operator from another variant of the same alternative types.
Definition variant.hpp:776
auto get() const &noexcept(!detail::are_exceptions_enabled_v) -> T const &
Get by type.
Definition variant.hpp:965
auto index() const noexcept -> std::size_t
Get the index of the alternative type that this variant currently holds.
Definition variant.hpp:856
Definition array_exceptions_disabled.cpp:11
constexpr auto get(variant< Ts... > const &&var) noexcept(!detail::are_exceptions_enabled_v) -> T const &&
Get value held by a variant by type.
Definition variant.hpp:1149
constexpr auto get(variant< Ts... > &&var) noexcept(!detail::are_exceptions_enabled_v) -> T &&
Get value held by a variant by type.
Definition variant.hpp:1135
constexpr auto get(variant< Ts... > &var) noexcept(!detail::are_exceptions_enabled_v) -> T &
Get value held by a variant by type.
Definition variant.hpp:1107
constexpr auto get(variant< Ts... > const &var) noexcept(!detail::are_exceptions_enabled_v) -> T const &
Get value held by a variant by type.
Definition variant.hpp:1121
constexpr auto holds_alternative(variant< Ts... > const &var) noexcept -> bool
Check if the variant holds a value of a given alternative type.
Definition variant.hpp:1233
constexpr auto get_if(variant< Ts... > *ptr) noexcept -> std::add_pointer_t< variant_alternative_t< I, variant< Ts... > > >
Attempt to get a pointer to the object held by the variant by index.
Definition variant.hpp:1244
constexpr auto get_if(variant< Ts... > const *ptr) noexcept -> std::add_pointer_t< variant_alternative_t< I, variant< Ts... > > const >
Attempt to get a pointer to the object held by the variant by index.
Definition variant.hpp:1261
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10