From 2bde0e62b2308fc2aa456cc712c362a30195cd4c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 2 Nov 2019 13:54:43 +0100 Subject: [PATCH] Downcasting facility refactoring --- doc/DESIGN.md | 61 +++++++++++++++----------- doc/downcast_1.png | Bin 0 -> 6620 bytes doc/downcast_2.png | Bin 0 -> 22448 bytes src/include/units/bits/downcasting.h | 8 ++-- src/include/units/bits/format_utils.h | 2 +- src/include/units/dimension.h | 10 ++--- src/include/units/math.h | 4 +- src/include/units/quantity.h | 10 ++--- src/include/units/unit.h | 10 ++--- 9 files changed, 58 insertions(+), 47 deletions(-) create mode 100644 doc/downcast_1.png create mode 100644 doc/downcast_2.png diff --git a/doc/DESIGN.md b/doc/DESIGN.md index 90514804..00a83039 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -157,7 +157,7 @@ helper: ```cpp template -struct derived_dimension : downcast_helper::type> {}; +struct derived_dimension : downcast_child::type> {}; ``` `Child` class template parameter is a part of a CRTP idiom and is used to provide a downcasting facility @@ -244,7 +244,7 @@ template: ```cpp template -struct coherent_derived_unit : downcast_helper>> { +struct coherent_derived_unit : downcast_child>> { static constexpr auto symbol = Symbol; using prefix_type = PrefixType; }; @@ -267,7 +267,7 @@ To create the rest of derived units the following class template can be used: ```cpp template -struct derived_unit : downcast_helper> { +struct derived_unit : downcast_child> { static constexpr auto symbol = Symbol; }; ``` @@ -286,7 +286,7 @@ For example to create a prefixed unit the following may be used: ```cpp template requires requires { U::symbol; } -struct prefixed_derived_unit : downcast_helper>> { static constexpr auto symbol = P::symbol + U::symbol; @@ -298,7 +298,7 @@ where `Prefix` is a concept requiring the instantiation of the following class t ```cpp template -struct prefix : downcast_helper> { +struct prefix : downcast_child> { static constexpr auto symbol = Symbol; }; ``` @@ -322,7 +322,7 @@ For the cases where determining the exact ratio is not trivial another helper ca ```cpp template -struct deduced_derived_unit : downcast_helper> { +struct deduced_derived_unit : downcast_child> { static constexpr auto symbol = Symbol; }; ``` @@ -541,20 +541,31 @@ and are not arguably much easier to understand thus provide better user experience. -Downcasting facility provides a type substitution mechanism. It connects a specific primary template -class specialization with a strong type assigned to it by the user. A simplified mental model of the -facility may be represented as: +When dealing with simple types, aliases can be easily replaced with inheritance: -```cpp -struct metre : unit>, std::ratio<1, 1, 0>>; -``` +![UML](downcast_1.png) + +As a result we get strong types. There are however a few issues with such an approach: +- generic code getting a child class does not easily know the exact template parameters of + the base class +- generic code after computing the instantiation of the class template does not know if + this is a base class in some hierarchy, and in case it is, it does not know how to + replace the base class template instantiation with a derived strong type. + +Downcasting facility provides such a type substitution mechanism. It connects a specific primary +template class instantiation with a strong type assigned to it by the user. + +Here is the overview of resulting class hierarchy for our example: + +![UML](downcast_2.png) In the above example `metre` is a downcasting target (child class) and a specific `unit` class -template specialization is a downcasting source (base class). The downcasting facility provides -1 to 1 tpe substitution mechanism. Only one child class can be created for a specific base class +template instantiation is a downcasting source (base class). The downcasting facility provides +1 to 1 type substitution mechanism. Only one child class can be created for a specific base class template instantiation. -Downcasting facility is provided through 2 dedicated types, a concept, and a few helper template aliases. +Downcasting facility is provided through 2 dedicated types, a concept, and a few helper template +aliases. ```cpp template @@ -568,7 +579,7 @@ struct downcast_base { facility with a `base_type` member type, and provides a declaration of downcasting ADL friendly (Hidden Friend) entry point member function `downcast_guide`. An important design point is that this function does not return any specific type in its declaration. This non-member function -is going to be defined in a child class template `downcast_helper` and will return a target +is going to be defined in a child class template `downcast_child` and will return a target type of the downcasting operation there. ```cpp @@ -585,24 +596,24 @@ facility. ```cpp template -struct downcast_helper : T { - friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); } +struct downcast_child : T { + friend auto downcast_guide(typename downcast_child::downcast_base) { return Target(); } }; ``` -`units::downcast_helper` is another CRTP class template that provides the implementation of a +`units::downcast_child` is another CRTP class template that provides the implementation of a non-member friend function of the `downcast_base` class template which defines the target type of a downcasting operation. It is used in the following way to define `dimension` and `unit` types in the library: ```cpp template -struct derived_dimension : downcast_helper> {}; +struct derived_dimension : downcast_child> {}; ``` ```cpp template -struct derived_unit : downcast_helper>> {}; +struct derived_unit : downcast_child>> {}; ``` With such CRTP types the only thing the user has to do to register a new type to the downcasting @@ -618,18 +629,18 @@ downcasting operation a dedicated template alias is provided: ```cpp template -using downcast_target = decltype(detail::downcast_target_impl()); +using downcast = decltype(detail::downcast_target_impl()); ``` -`units::downcast_target` is used to obtain the target type of the downcasting operation registered -for a given specialization in a base type. +`units::downcast` is used to obtain the target type of the downcasting operation registered +for a given instantiation in a base type. For example to determine a downcasted type of a quantity multiply operation the following can be done: ```cpp using dim = dimension_multiply; using common_rep = decltype(lhs.count() * rhs.count()); -using ret = quantity>>, common_rep>; +using ret = quantity>>, common_rep>; ``` `detail::downcast_target_impl` checks if a downcasting target is registered for the specific base class. diff --git a/doc/downcast_1.png b/doc/downcast_1.png new file mode 100644 index 0000000000000000000000000000000000000000..227681970d93e0b4f3a6aa9ad243820316fc9329 GIT binary patch literal 6620 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 BrB?s| literal 0 HcmV?d00001 diff --git a/doc/downcast_2.png b/doc/downcast_2.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbfc6c23bebc0e7aa28c5b554c9c8f9d5de5f4e GIT binary patch literal 22448 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 My85}Sb4q9e06gAz2LJ#7 literal 0 HcmV?d00001 diff --git a/src/include/units/bits/downcasting.h b/src/include/units/bits/downcasting.h index f5bf3779..043b1522 100644 --- a/src/include/units/bits/downcasting.h +++ b/src/include/units/bits/downcasting.h @@ -41,8 +41,8 @@ namespace units { std::derived_from>; template - struct downcast_helper : T { - friend auto downcast_guide(typename downcast_helper::downcast_base) { return Target(); } + struct downcast_child : T { + friend auto downcast_guide(typename downcast_child::downcast_base) { return Target(); } }; namespace detail { @@ -53,7 +53,7 @@ namespace units { }; template - constexpr auto downcast_target_impl() + constexpr auto downcast_impl() { if constexpr(has_downcast) return decltype(downcast_guide(std::declval>()))(); @@ -64,7 +64,7 @@ namespace units { } template - using downcast_target = decltype(detail::downcast_target_impl()); + using downcast = decltype(detail::downcast_impl()); template using downcast_base_t = T::base_type; diff --git a/src/include/units/bits/format_utils.h b/src/include/units/bits/format_utils.h index a16f384f..2749e87c 100644 --- a/src/include/units/bits/format_utils.h +++ b/src/include/units/bits/format_utils.h @@ -48,7 +48,7 @@ namespace units { { if constexpr(Ratio::num != 1 || Ratio::den != 1) { if(!std::same_as) { - using prefix = downcast_target>; + using prefix = downcast>; if constexpr(!std::same_as>) { // print as a prefixed unit diff --git a/src/include/units/dimension.h b/src/include/units/dimension.h index 9d73a2f9..ed4add42 100644 --- a/src/include/units/dimension.h +++ b/src/include/units/dimension.h @@ -151,7 +151,7 @@ namespace units { struct dim_invert_impl; template - struct dim_invert_impl> : std::type_identity...>>> {}; + struct dim_invert_impl> : std::type_identity...>>> {}; } @@ -221,7 +221,7 @@ namespace units { // derived_dimension template - struct derived_dimension : downcast_helper::type> {}; + struct derived_dimension : downcast_child> {}; // merge_dimension namespace detail { @@ -243,7 +243,7 @@ namespace units { struct dimension_multiply_impl; template - struct dimension_multiply_impl, dimension> : std::type_identity, dimension>>> {}; + struct dimension_multiply_impl, dimension> : std::type_identity, dimension>>> {}; } @@ -273,7 +273,7 @@ namespace units { struct dimension_sqrt_impl; template - struct dimension_sqrt_impl> : std::type_identity...>>> {}; + struct dimension_sqrt_impl> : std::type_identity...>>> {}; } @@ -287,7 +287,7 @@ namespace units { struct dimension_pow_impl; template - struct dimension_pow_impl, N> : std::type_identity...>>> {}; + struct dimension_pow_impl, N> : std::type_identity...>>> {}; } diff --git a/src/include/units/math.h b/src/include/units/math.h index 3dd70d92..1fd79d17 100644 --- a/src/include/units/math.h +++ b/src/include/units/math.h @@ -39,7 +39,7 @@ namespace units { { using dim = dimension_pow; using r = ratio_pow; - return quantity>, Rep>(static_cast(std::pow(q.count(), N))); + return quantity>, Rep>(static_cast(std::pow(q.count(), N))); } template @@ -47,7 +47,7 @@ namespace units { { using dim = dimension_sqrt; using r = ratio_sqrt; - return quantity>, Rep>(static_cast(std::sqrt(q.count()))); + return quantity>, Rep>(static_cast(std::sqrt(q.count()))); } } // namespace units diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 86e45630..14097d77 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -76,7 +76,7 @@ namespace units { requires same_dim struct common_quantity_impl, quantity, Rep> { using type = - quantity>>, + quantity>>, Rep>; }; @@ -291,7 +291,7 @@ namespace units { using dim = quantity::unit::dimension; if constexpr(!detail::is_dimension) { // print as a prefix or ratio of a coherent unit symbol defined by the user - using coherent_unit = downcast_target>>; + using coherent_unit = downcast>>; detail::print_prefix_or_ratio(os); os << coherent_unit::symbol; } @@ -358,7 +358,7 @@ namespace units { { using dim = dimension_multiply; using common_rep = decltype(lhs.count() * rhs.count()); - using ret = quantity>>, common_rep>; + using ret = quantity>>, common_rep>; return ret(lhs.count() * rhs.count()); } @@ -370,9 +370,9 @@ namespace units { using dim = dim_invert; using common_rep = decltype(v / q.count()); - using ret = quantity>>, common_rep>; using den = quantity; return ret(v / den(q).count()); + using ret = quantity>>, common_rep>; } template @@ -407,7 +407,7 @@ namespace units { using common_rep = decltype(lhs.count() / rhs.count()); using dim = dimension_divide; - using ret = quantity>>, common_rep>; + using ret = quantity>>, common_rep>; return ret(lhs.count() / rhs.count()); } diff --git a/src/include/units/unit.h b/src/include/units/unit.h index d451961b..b75aeb93 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -63,7 +63,7 @@ namespace units { } template - struct prefix : downcast_helper> { + struct prefix : downcast_child> { static constexpr auto symbol = Symbol; }; @@ -150,25 +150,25 @@ namespace units { struct no_prefix; template - struct coherent_derived_unit : downcast_helper>> { + struct coherent_derived_unit : downcast_child>> { static constexpr auto symbol = Symbol; using prefix_type = PrefixType; }; template - struct derived_unit : downcast_helper> { + struct derived_unit : downcast_child> { static constexpr auto symbol = Symbol; }; template requires requires { U::symbol; } - struct prefixed_derived_unit : downcast_helper>> { + struct prefixed_derived_unit : downcast_child>> { static constexpr auto symbol = P::symbol + U::symbol; using prefix_type = P::prefix_type; }; template - struct deduced_derived_unit : downcast_helper> { + struct deduced_derived_unit : downcast_child> { static constexpr auto symbol = Symbol; };