Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
combine_kinds.hpp
Go to the documentation of this file.
1// Copyright 2026, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_COMBINE_KINDS_HPP_
5#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_COMBINE_KINDS_HPP_
6
7#include "arene/base/constraints/constraints.hpp"
8#include "arene/base/stdlib_choice/cstddef.hpp"
9#include "arene/base/stdlib_choice/cstdint.hpp"
10#include "arene/base/stdlib_choice/enable_if.hpp"
11#include "arene/base/stdlib_choice/integral_constant.hpp"
12#include "arene/base/stdlib_choice/is_same.hpp"
13#include "arene/base/type_info/type_name_string.hpp"
14#include "arene/base/type_list/apply_all.hpp"
15#include "arene/base/type_list/sort.hpp"
16#include "arene/base/type_list/type_list.hpp"
17#include "arene/base/type_traits/all_of.hpp"
18#include "arene/base/type_traits/conditional.hpp"
19#include "arene/base/type_traits/is_instantiation_of.hpp"
20#include "arene/base/units/base_kind_set.hpp"
21#include "arene/base/units/detail/is_bipartite_match.hpp"
22#include "arene/base/units/detail/missing.hpp"
23#include "arene/base/units/detail/sum.hpp"
24#include "arene/base/units/explicit_base_set.hpp"
25#include "arene/base/units/is_base_quantity_kind.hpp"
26#include "arene/base/units/is_kind_with_exponent.hpp"
27#include "arene/base/units/is_quantity_kind.hpp"
28#include "arene/base/units/is_unit.hpp"
29#include "arene/base/units/kind_with_exponent_fwd.hpp"
30#include "arene/base/units/quantity_kind.hpp"
31#include "arene/base/units/quantity_unit.hpp"
32#include "arene/base/units/scaled_unit.hpp"
33#include "arene/base/units/unit_kind.hpp"
34
35namespace arene {
36namespace base {
37
38namespace combine_kinds_detail {
39
40/// @brief A helper template to convert a quantity kind raised to an exponent of 1 to just that quantity kind
41/// @tparam Kind the quantity kind to unpack
42template <typename Kind>
43class unpack_unit_exponent_helper {
44 public:
45 /// @brief The unpacked quantity kind
46 using type = Kind;
47};
48
49/// @brief A helper template to convert a quantity kind raised to an exponent of 1 to just that quantity kind
50/// @tparam Kind the quantity kind to unpack
51template <typename Kind>
52class unpack_unit_exponent_helper<units_detail::quantity_kind_with_exponent<Kind, 1, 0>> {
53 public:
54 /// @brief The unpacked quantity kind
55 using type = Kind;
56};
57
58/// @brief A helper template to convert a quantity kind raised to an exponent of 1 to just that quantity kind
59/// @tparam Kind the quantity kind to unpack
60template <typename Kind>
61using unpack_unit_exponent_t = typename unpack_unit_exponent_helper<Kind>::type;
62
63/// @brief Helper template to select the base class of a combined quantity kind
64/// @tparam CombinedKind the derived combined quantity kind
65template <typename CombinedKind, typename = constraints<>>
66class combine_kind_base_helper {
67 public:
68 /// @brief The base class
69 using type = quantity_kind<CombinedKind>;
70};
71
72/// @brief A template that represents a quantity kind that is a combination of base quantity kinds
73/// @tparam BaseKinds The base quantity kinds to combine
74template <typename... BaseKinds>
75class combined_quantity_kind : public combine_kind_base_helper<combined_quantity_kind<BaseKinds...>>::type {
76 static_assert(all_of_v<is_quantity_kind_v<BaseKinds>...>, "All combined elements must be valid quantity kinds");
77
78 public:
79 /// @brief Denotes that quantity kind is implicit and does not mark a
80 /// boundary when aggregating and simplifying quantity kind types.
81 using is_implicit = void;
82};
83
84/// @brief A helper template to normalize a quantity kind ready for combining
85/// @tparam Kind the quantity kind to normalize
86template <typename Kind>
87class normalize_for_combining_helper {
88 public:
89 /// @brief The normalized quantity kind
90 using type = units_detail::quantity_kind_with_exponent<Kind, 1, 0>;
91};
92
93/// @brief A type alias for a normalized quantity kind ready for combining
94/// @tparam Kind the quantity kind to normalize
95///
96/// This converts all plain quantity kinds into a @c quantity_kind_with_exponent with an exponent of 1, so that the
97/// logic for combining kinds only needs to deal with comparing and merging exponents. After the types have been
98/// combined, @c unpack_unit_exponent_t is then used to convert any remaining instances of @c
99/// quantity_kind_with_exponent with an exponent of 1 back into their base kind.
100template <typename Kind>
101using normalize_for_combining_t = typename normalize_for_combining_helper<Kind>::type;
102
103/// @brief A helper template to normalize a quantity kind ready for combining
104/// @tparam Kind the base quantity kind of a kind raised to an exponent being normalized
105/// @tparam PositiveExponent the positive exponent the kind is raised to
106/// @tparam NegativeExponent the negative exponent the kind is raised to
107template <typename Kind, units_detail::exponent_t PositiveExponent, units_detail::exponent_t NegativeExponent>
108class normalize_for_combining_helper<
109 units_detail::quantity_kind_with_exponent<Kind, PositiveExponent, NegativeExponent>> {
110 public:
111 /// @brief The normalized quantity kind
112 using type = units_detail::quantity_kind_with_exponent<Kind, PositiveExponent, NegativeExponent>;
113};
114
115/// @brief A helper template to normalize a quantity kind ready for combining
116/// @tparam Kind the base quantity kind of a kind raised to an exponent being normalized
117/// @tparam PositiveExponent the positive exponent the kind is raised to
118/// @tparam NegativeExponent the negative exponent the kind is raised to
119///
120/// Combination logic uses the explicit base set to combine quantity kinds
121/// across multiple types. However, we need to temporarily wrap scaled units to
122/// preserve them.
123template <typename BaseUnit, typename Scale>
124class normalize_for_combining_helper<scaled_unit_detail::scaled_unit_impl<BaseUnit, Scale>> {
125 public:
126 /// @brief The normalized quantity kind
127 using type = units_detail::quantity_kind_with_exponent<
128 units_detail::explicit_base_barrier<scaled_unit_detail::scaled_unit_impl<BaseUnit, Scale>>,
129 1,
130 0>;
131};
132
133/// @brief A helper template to normalize a quantity kind ready for combining
134/// @tparam Kinds the quantity kinds that are already combined
135template <typename... Kinds>
136class normalize_for_combining_helper<combined_quantity_kind<Kinds...>> {
137 public:
138 /// @brief The normalized quantity kind
139 using type = combined_quantity_kind<normalize_for_combining_t<Kinds>...>;
140};
141
142/// @brief Helper template that compares two quantity kinds to determine which should be ordered before the other when
143/// combining
144/// @tparam LhsKind The left-hand kind being compared
145/// @tparam RhsKind The right-hand kind being compared
146template <typename LhsKind, typename RhsKind>
147class kind_sorts_before {
148 public:
149 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "This member is the public API"
150 // parasoft-begin-suppress CERT_CPP-DCL56-a "False positive: type_name_v is initialized"
151 /// @brief The result of the comparison
152 static constexpr bool value{type_name_v<LhsKind> < type_name_v<RhsKind>};
153 // parasoft-end-suppress CERT_CPP-DCL56-a
154 // parasoft-end-suppress AUTOSAR-M11_0_1-a
155};
156
157/// @brief Helper template that compares two quantity kinds to determine which should be ordered before the other when
158/// combining. The important part is that this groups all instances with the same base quantity kind together, to make
159/// it easier to combine them; the ordering on the exponents is to make the order stable.
160/// @tparam LhsKind The base kind of the left-hand kind being compared
161/// @tparam LhsPositiveExponent The positive exponent of the left-hand kind being compared
162/// @tparam LhsNegativeExponent The negative exponent of the left-hand kind being compared
163/// @tparam RhsKind The base kind of the right-hand kind being compared
164/// @tparam RhsPositiveExponent The positive exponent of the right-hand kind being compared
165/// @tparam RhsNegativeExponent The negative exponent of the right-hand kind being compared
166template <
167 typename LhsKind,
168 units_detail::exponent_t LhsPositiveExponent,
169 units_detail::exponent_t LhsNegativeExponent,
170 typename RhsKind,
171 units_detail::exponent_t RhsPositiveExponent,
172 units_detail::exponent_t RhsNegativeExponent>
173class kind_sorts_before<
174 units_detail::quantity_kind_with_exponent<LhsKind, LhsPositiveExponent, LhsNegativeExponent>,
175 units_detail::quantity_kind_with_exponent<RhsKind, RhsPositiveExponent, RhsNegativeExponent>> {
176 public:
177 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "This member is the public API"
178 // parasoft-begin-suppress CERT_CPP-DCL56-a "False positive: type_name_v is initialized"
179 /// @brief The result of the comparison
180 static constexpr bool value{
181 (type_name_v<LhsKind> < type_name_v<RhsKind>) ||
182 ((type_name_v<LhsKind> == type_name_v<RhsKind>)&&(
183 (LhsPositiveExponent < RhsPositiveExponent) ||
184 ((LhsPositiveExponent == RhsPositiveExponent) && (LhsNegativeExponent < RhsNegativeExponent))
185 ))
186 };
187 // parasoft-end-suppress CERT_CPP-DCL56-a
188 // parasoft-end-suppress AUTOSAR-M11_0_1-a
189};
190
191/// @brief Helper template to strip any unnecessary @c combined_quantity_kind or @c quantity_kind_with_exponent wrappers
192/// @tparam Kinds the @c combined_quantity_kind wrapper being stripped
193template <typename Kind>
194class canonicalize_post_combining {
195 public:
196 /// @brief quantity kind type
197 using type = Kind;
198};
199
200/// @brief Helper template to strip any unnecessary @c combined_quantity_kind or @c quantity_kind_with_exponent wrappers
201/// @tparam Kinds the quantity kinds in the list
202template <typename... Kinds>
203class canonicalize_post_combining<combined_quantity_kind<Kinds...>> {
204 public:
205 /// @brief The stripped kind
206 using type = combined_quantity_kind<typename canonicalize_post_combining<Kinds>::type...>;
207};
208
209/// @brief Helper template to strip any unnecessary @c combined_quantity_kind or @c quantity_kind_with_exponent wrappers
210/// @tparam Kind the single quantity kind in the list
211template <typename Kind>
212class canonicalize_post_combining<combined_quantity_kind<Kind>> : public canonicalize_post_combining<Kind> {};
213
214/// @brief Helper template to strip any unnecessary @c combined_quantity_kind or @c quantity_kind_with_exponent wrappers
215template <typename Kind, units_detail::exponent_t PositiveExponent, units_detail::exponent_t NegativeExponent>
216class canonicalize_post_combining<units_detail::quantity_kind_with_exponent<Kind, PositiveExponent, NegativeExponent>> {
217 public:
218 /// @brief simplified quantity kind type
219 using type = conditional_t<
220 (PositiveExponent == 1 && NegativeExponent == 0),
221 typename canonicalize_post_combining<Kind>::type,
222 units_detail::quantity_kind_with_exponent<
223 typename canonicalize_post_combining<Kind>::type,
224 PositiveExponent,
225 NegativeExponent>>;
226};
227
228/// @brief Helper template to strip any unnecessary @c combined_quantity_kind or @c quantity_kind_with_exponent wrappers
229/// @tparam Kind quantity kind
230///
231/// Unwrap any barriers introduced when determining the explicit base set.
232template <typename Kind>
233class canonicalize_post_combining<units_detail::explicit_base_barrier<Kind>> {
234 public:
235 /// @brief quantity kind type
236 using type = Kind;
237};
238
239/// @brief Helper type sort a list of quantity kinds and combine them
240/// @tparam Kinds the quantity kinds to combine
241/// Provides the combined quantity kind types in combined normal form.
242template <typename... Kinds>
243class internal_combine_kinds {
244 /// @brief defines the combined explicit base sets of @c Kinds
245 struct explicit_base_set_union {
246 // parasoft-begin-suppress AUTOSAR-A3_3_2-a "False positive: variable 'value' is initialized"
247 // parasoft-begin-suppress CERT_CPP-DCL56-a "False positive: variable 'value' is initialized"
248 /// @brief explicit bases set for @c Kinds...
249 static constexpr auto value = units_detail::set_union(units_detail::explicit_base_set<Kinds>...);
250 // parasoft-end-suppress AUTOSAR-A3_3_2-a
251 // parasoft-end-suppress CERT_CPP-DCL56-a
252 };
253
254 public:
255 /// @brief the combined quantity kind in combined normal form
256 using type = type_lists::apply_all_t<
257 type_lists::sort_t<
258 units_detail::as_list_of_kinds_with_exponents_t<explicit_base_set_union>,
259 combine_kinds_detail::kind_sorts_before>,
260 combined_quantity_kind>;
261};
262
263/// @brief Helper type to sort a list of quantity kinds and combine them
264/// @tparam Kinds the quantity kinds to combine
265/// Provides the combined quantity kind types in combined normal form.
266template <typename... Kinds>
267using internal_combine_kinds_t = typename internal_combine_kinds<Kinds...>::type;
268
269} // namespace combine_kinds_detail
270
271/// @brief Template alias to combine a list of quantity kinds
272/// @tparam Kinds the quantity kinds to combine
273template <typename... Kinds>
278 >::type //
279 >::type;
280
281namespace units_detail {
282
283/// @brief Helper class to determine the result of raising a combined quantity kind to a positive and negative exponent
284/// @tparam BaseKinds The quantity kinds to raise to an exponent
285/// @tparam PositiveExponent The positive exponent to raise it to
286/// @tparam NegativeExponent The negative exponent to raise it to
287template <typename... BaseKinds, exponent_t PositiveExponent, exponent_t NegativeExponent>
288class kind_with_exponent_helper<
289 combine_kinds_detail::combined_quantity_kind<BaseKinds...>,
290 PositiveExponent,
291 NegativeExponent,
292 // negated expr matches constraint for other specialization
293 // NOLINTNEXTLINE(readability-simplify-boolean-expr)
294 constraints<std::enable_if_t<!(PositiveExponent == 1 && NegativeExponent == 0)>>> {
295 public:
296 /// @brief An alias for a quantity kind representing the combined quantity kind raised to the specified exponents
297 using type =
298 combine_kinds_t<typename kind_with_exponent_helper<BaseKinds, PositiveExponent, NegativeExponent>::type...>;
299};
300
301} // namespace units_detail
302
303namespace combine_kinds_detail {
304
305/// @brief Helper template to select the base class of a combined quantity kind
306/// @tparam BaseKinds the individual quantity kinds that are combined in the derived quantity kind
307///
308/// This specialization handles the case that the kinds being combined are all units, so the result is a unit
309template <typename... BaseKinds>
310class combine_kind_base_helper<
311 combined_quantity_kind<BaseKinds...>,
312 constraints<std::enable_if_t<all_of_v<is_unit_v<BaseKinds>...>>>> {
313 public:
314 /// @brief The base class
315 using type = quantity_unit< //
316 combined_quantity_kind<BaseKinds...>,
317 combine_kinds_t<unit_kind_t<BaseKinds>...>>;
318};
319
320/// @brief obtain a quantity kind with exponent values
321/// @tparam Kind quantity kind type
322///
323/// Primary template specifying a quantity kind with positive exponent 1.
324template <class Kind>
325class with_exponent {
326 public:
327 /// @brief quantity kind with exponent
328 using type = units_detail::quantity_kind_with_exponent<Kind, 1, 0>;
329};
330
331/// @brief obtain a quantity kind with exponent values
332/// @tparam Kind quantity kind type
333/// @tparam Positive positive expoenent
334/// @tparam Negative negative expoenent
335///
336/// Template specialization for a quantity kind that is already a specialization of @c quantity_kind_with_exponent
337template <class Kind, units_detail::exponent_t Positive, units_detail::exponent_t Negative>
338class with_exponent<units_detail::quantity_kind_with_exponent<Kind, Positive, Negative>> {
339 public:
340 /// @brief quantity kind with exponent
341 using type = units_detail::quantity_kind_with_exponent<Kind, Positive, Negative>;
342};
343
344/// @brief obtain a quantity kind with exponent values
345/// @tparam Kind quantity kind type
346template <typename Kind>
347using with_exponent_t = typename with_exponent<Kind>::type;
348
349/// @brief polarity states allowing independent analysis of
350/// positive/negative/zero quantity kind exponents
351enum class polarity : std::uint8_t {
352 /// @brief corresponds to quantity kinds with negative exponent values
353 negative,
354 /// @brief corresponds to special case of quantity kinds with 0 positive and 0 negative exponent values
355 zero,
356 /// @brief corresponds to quantity kinds with positive exponent values
357 positive
358};
359
360/// @brief extracts a single exponent value of a quantity kind
361/// @tparam Sign polarity sign
362/// @tparam KindWithExponent quantity kind with exponents
363template <polarity Sign, class KindWithExponent>
364struct polarity_wrapper;
365
366/// @brief extracts a single exponent value of a quantity kind
367/// @tparam Kind quantity kind
368/// @tparam Positive positive exponent value
369/// @tparam Negative negative exponent value
370///
371/// Specialization for negative exponents.
372template <typename Kind, units_detail::exponent_t Positive, units_detail::exponent_t Negative>
373struct polarity_wrapper<polarity::negative, units_detail::quantity_kind_with_exponent<Kind, Positive, Negative>> {
374 /// @brief polarity sign
375 static constexpr auto sign = polarity::negative;
376 // parasoft-begin-suppress AUTOSAR-M5_0_4-a "No implementation-defined behavior in this constant expression"
377 /// @brief number of powers with the same sign
378 static constexpr std::size_t count{Negative};
379 // parasoft-end-suppress AUTOSAR-M5_0_4-a
380 /// @brief quantity kind
381 using quantity_kind_type = Kind;
382};
383
384/// @brief extracts a single exponent value of a quantity kind
385/// @tparam Kind quantity kind
386/// @tparam Positive positive exponent value
387/// @tparam Negative negative exponent value
388///
389/// Specialization for zero exponents.
390template <typename Kind, units_detail::exponent_t Positive, units_detail::exponent_t Negative>
391struct polarity_wrapper<polarity::zero, units_detail::quantity_kind_with_exponent<Kind, Positive, Negative>> {
392 /// @brief polarity sign
393 static constexpr auto sign = polarity::zero;
394 // parasoft-begin-suppress AUTOSAR-A5_16_1-a "False positive: Conditional operator not used as subexpression"
395 /// @brief number of powers with the same sign
396 /// This handles the special case where a quantity kind explicitly has a 0
397 /// positive exponent and a 0 negative exponent.
398 static constexpr std::size_t count{((Positive == 0) && (Negative == 0)) ? 1U : 0U};
399 // parasoft-end-suppress AUTOSAR-A5_16_1-a
400 /// @brief quantity kind
401 using quantity_kind_type = Kind;
402};
403
404/// @brief extracts a single exponent value of a quantity kind
405/// @tparam Kind quantity kind
406/// @tparam Positive positive exponent value
407/// @tparam Negative negative exponent value
408///
409/// Specialization for positive exponents.
410template <typename Kind, units_detail::exponent_t Positive, units_detail::exponent_t Negative>
411struct polarity_wrapper<polarity::positive, units_detail::quantity_kind_with_exponent<Kind, Positive, Negative>> {
412 /// @brief polarity sign
413 static constexpr auto sign = polarity::positive;
414 // parasoft-begin-suppress AUTOSAR-M5_0_4-a "No implementation-defined behavior in this constant expression"
415 /// @brief number of powers with the same sign
416 static constexpr std::size_t count{Positive};
417 // parasoft-end-suppress AUTOSAR-M5_0_4-a
418 /// @brief quantity kind
419 using quantity_kind_type = Kind;
420};
421
422/// @brief determine if a kind is a sink for another
423/// @tparam Source source polarity wrapped quantity kind
424/// @tparam Sink sink polarity wrapped quantity kind
425///
426/// @c Sink is a sink for @c Source if they have the same polarity and the @c
427/// Sink::quantity_kind_type is the same or a base quantity kind of @c
428/// Source::quantity_kind_type.
429template <typename Source, typename Sink>
430using is_kind_sink = std::integral_constant<
431 bool,
432 ((Source::sign == Sink::sign) &&
433 (std::is_same<typename Source::quantity_kind_type, typename Sink::quantity_kind_type>::value ||
434 is_base_quantity_kind_of_v<typename Sink::quantity_kind_type, typename Source::quantity_kind_type>))>;
435
436/// @brief determine is there is a bijective bipartite match for two sets of types
437/// @tparam Sign polarity sign
438/// @tparam Sources source quantity kind types
439/// @tparam Sink sink quantity kind types
440///
441/// Dummy primary template
442template <polarity Sign, typename Sources, typename Sinks>
443extern constexpr auto has_pairwise_match_v = units_detail::missing{};
444
445/// @brief helper to ensure that types are unique
446/// @tparam Ts types
447///
448/// Helper used to ensure that quantity kind types are correctly grouped. Causes
449/// a hard error if a type is duplicated.
450template <typename... Ts>
451class error_if_duplicate_types : Ts... {};
452
453/// @brief determine is there is a bijective bipartite match for two sets of types
454/// @tparam Sign polarity sign
455/// @tparam Sources source quantity kind types
456/// @tparam Sink sink quantity kind types
457template <polarity Sign, typename... Sources, typename... Sinks>
458extern constexpr bool has_pairwise_match_v<
459 Sign,
460 type_list<Sources...>,
461 type_list<Sinks...>> //
462 {
463 (error_if_duplicate_types<typename Sources::quantity_kind_type...>{}, true) &&
464 (error_if_duplicate_types<typename Sinks::quantity_kind_type...>{}, true) &&
465 (units_detail::sum({polarity_wrapper<Sign, with_exponent_t<Sources>>::count...}) ==
466 units_detail::sum({polarity_wrapper<Sign, with_exponent_t<Sinks>>::count...})) &&
467 units_detail::is_bipartite_match_v< //
468 type_list<polarity_wrapper<Sign, with_exponent_t<Sources>>...>, //
469 type_list<polarity_wrapper<Sign, with_exponent_t<Sinks>>...>, //
470 is_kind_sink> //
471 };
472
473} // namespace combine_kinds_detail
474
475namespace is_base_quantity_kind_detail {
476
477/// @brief Type trait for checking if one type is a base quantity kind for another. Evaluates to @c true if the first
478/// type is a base quantity kind of the second (the second is a derived quantity kind of the first), @c false otherwise
479/// @tparam BaseKinds the quantity kinds combined for the base quantity kind
480/// @tparam CheckKinds the quantity kinds combined for the quantity kind to be checked
481///
482/// For combined quantity kinds, one kind is a base kind of the other if they are not the same, they have the same
483/// number of elements, and for the elements can be paired off such that there is a corresponding element from the
484/// former that is the same as or a base of each element of the latter.
485template <typename... BaseKinds, typename... CheckKinds>
486extern constexpr bool is_base_quantity_kind_of_v<
487 combine_kinds_detail::combined_quantity_kind<BaseKinds...>,
488 combine_kinds_detail::combined_quantity_kind<CheckKinds...>,
489 constraints< //
490 std::enable_if_t< //
491 !std::is_same<
492 combine_kinds_detail::combined_quantity_kind<BaseKinds...>,
493 combine_kinds_detail::combined_quantity_kind<CheckKinds...>>::value>>> //
494 {
495 combine_kinds_detail::has_pairwise_match_v< //
496 combine_kinds_detail::polarity::negative, //
497 type_list<CheckKinds...>, //
498 type_list<BaseKinds...>> //
499 && combine_kinds_detail::has_pairwise_match_v< //
500 combine_kinds_detail::polarity::zero, //
501 type_list<CheckKinds...>, //
502 type_list<BaseKinds...>> //
503 && combine_kinds_detail::has_pairwise_match_v< //
504 combine_kinds_detail::polarity::positive, //
505 type_list<CheckKinds...>, //
506 type_list<BaseKinds...>> //
507 };
508
509/// @brief Type trait for checking if one type is a base quantity kind for another. Evaluates to @c true if the first
510/// type is a base quantity kind of the second (the second is a derived quantity kind of the first), @c false otherwise
511/// @tparam BaseKind the quantity kind raised to the exponent for the base quantity kind
512/// @tparam PositiveExponent the positive exponent for the base quantity kind
513/// @tparam NegativeExponent the negative exponent for the base quantity kind
514/// @tparam CheckKinds the quantity kinds combined for the quantity kind to be checked
515///
516/// A kind with exponent is the base of a combined kind if each of the combined elements are derived from that base with
517/// the right total exponents
518template <
519 typename BaseKind,
520 typename... CheckKinds>
521extern constexpr bool is_base_quantity_kind_of_v< //
522 BaseKind,
523 combine_kinds_detail::combined_quantity_kind<CheckKinds...>,
524 constraints< //
525 std::enable_if_t< //
526 !is_instantiation_of_v<
527 BaseKind,
528 combine_kinds_detail::combined_quantity_kind>>>> //
529 {
530 is_base_quantity_kind_of_v< //
531 combine_kinds_detail::combined_quantity_kind<BaseKind>, //
532 combine_kinds_detail::combined_quantity_kind<CheckKinds...>> //
533 };
534
535/// @brief Type trait for checking if one type is a base quantity kind for another. Evaluates to @c true if the first
536/// type is a base quantity kind of the second (the second is a derived quantity kind of the first), @c false otherwise
537/// @tparam BaseKinds the quantity kinds combined for the base quantity kind
538/// @tparam CheckKind the quantity kind raised to the exponent for the quantity kind to check
539/// @tparam PositiveExponent the positive exponent for the quantity kind to check
540/// @tparam NegativeExponent the negative exponent for the quantity kind to check
541///
542/// A combined kind is the base for a kind with exponent if each of the combined kinds is a base for the kind with
543/// exponent, with the appropriate total exponents
544template <typename... BaseKinds, typename CheckKind>
545extern constexpr bool is_base_quantity_kind_of_v<
546 combine_kinds_detail::combined_quantity_kind<BaseKinds...>,
547 CheckKind,
548 constraints< //
549 std::enable_if_t<units_detail::is_kind_with_exponent_v<CheckKind>>, //
550 std::enable_if_t< //
551 !is_base_quantity_kind_of_v< //
552 combine_kinds_detail::combined_quantity_kind<BaseKinds...>, //
553 typename CheckKind::parent_quantity_kind_type>> //
554 >> //
555 {
556 is_base_quantity_kind_of_v< //
557 combine_kinds_detail::combined_quantity_kind<BaseKinds...>, //
558 combine_kinds_detail::combined_quantity_kind<CheckKind>> //
559 };
560
561} // namespace is_base_quantity_kind_detail
562
563} // namespace base
564} // namespace arene
565
566#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_COMBINE_KINDS_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10