1

Given this types:

template<Ratio r, Symbol s>
struct base_unit {
    using ratio = r;
    using symbol = s;
};

template <BaseUnit... baseUnits>
struct derived_unit {
    using units = std::tuple<baseUnits...>;
};

If, for example, I have a type like:

template <typename T>
struct Computations {
    using collection_ratios = /* */
    static constexpr ratios_product = /* */
}

I wanted to know how can I:

  • store all the ratios for a given derived_unit in a container like std::array<T, N> with a fold expression (collection_ratios)
  • store the result of multiply every element in the units member of derived_unit and store it in a variable with a fold expression (ratios_product)

Edit:

Where T is a specialization of derived_unit, like, for example:

struct MetersPerSecond :
   public speed,
   public derived_unit<         
        base_unit<Kilo, m>,
        base_unit<Root, s>
   >
{};

Edit 2:

template <typename T>
concept RatioV = (std::is_integral_v<T> || std::is_floating_point_v<T>)
    && !std::is_same_v<T, char>;


consteval double getFactor(double base, double exponent);

template <RatioV T = short, T Base = 10, T Exponent = 0>
struct ratio {
    static constexpr T base = Base;
    static constexpr T exponent = Exponent;
    static constexpr T value = getFactor(base, exponent);
};

consteval double getFactor(double base, double exponent) {
    double result = 1;
    for (int i = 0; i < exponent; i++)
        result *= base;
    return result;
}

using Yocto = ratio<short, 10, -24>;
using Zepto = ratio<short, 10, -21>;
using Atto = ratio<short, 10, -18>;
using Femto = ratio<short, 10, -15>;
using Pico = ratio<short, 10, -12>;
using Nano = ratio<short, 10, -9>;
using Micro = ratio<short, 10, -6>;
using Milli = ratio<short, 10, -3>;
using Centi = ratio<short, 10, -2>;
using Deci = ratio<short, 10, -1>;
using Root = ratio<short, 10, 0>;
using Deca = ratio<short, 10, 1>;
using Hecto = ratio<short, 10, 2>;
using Kilo = ratio<short, 10, 3>;
using Mega = ratio<short, 10, 6>;
using Giga = ratio<short, 10, 9>;
using Tera = ratio<short, 10, 12>;
using Peta = ratio<short, 10, 15>;
using Exa = ratio<short, 10, 18>;
using Zetta = ratio<short, 10, 21>;
using Yotta = ratio<short, 10, 24>;
Alex Vergara
  • 1,766
  • 1
  • 10
  • 29
  • What is `T` here—a specialization of `derived_unit`? – Davis Herring Mar 29 '23 at 18:07
  • @DavisHerring sure it is. I updated the post with more info – Alex Vergara Mar 29 '23 at 18:16
  • There are no values anywhere in your definitions. What exactly do you want multiplied? – Not a real meerkat Mar 29 '23 at 23:42
  • How do you want a caller to do? Please provide an example of pseudo code for what you want to achieve. At least demonstrate what you want to mutiply in text example with a expected result. I don't get how to multiply `Root` and `Kilo`. Seems like `base_unit` represents kilo meter. There are no built-in types `Kilo`, `m`, `Root`, or `s` in C++. Context seems not clear enough. All the structs in example have only types instead of values (where is *ratio* in the example?). Then what should "multiple" do has to be defined. – Louis Go Mar 30 '23 at 01:22

1 Answers1

1

Is this what you are looking for?

All it does is get the list of ratio types into collection_ratios. And using that list, multiples all of the static value's into ratios_product.

template<typename Tuple>
struct ratios;

template<typename... Ts>
struct ratios<std::tuple<Ts...>> {
    using type = std::tuple<typename Ts::ratio...>;
};

template <typename Tuple>
struct ratios_product_impl;

template<typename... Ts>
struct ratios_product_impl<std::tuple<Ts...>>
{
    static constexpr auto value = (1 * ... * Ts::value);
};

template <typename T>
struct Computations {
    using collection_ratios = typename ratios<typename T::units>::type;

    // Calculates the product of all ratio values.
    static constexpr auto ratios_product = ratios_product_impl<collection_ratios>::value;
};

#include <iostream>

int main() {
    Computations<MetersPerSecond> c;
    std::cout << c.ratios_product; // Prints 10000 for MetersPerSecond.
    return 0;
}
Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55
  • Thanks for your answer. I edited the post in order to add the definitions for the ratios, since they are the important part here. For the second question, what I am looking for is for the way of write a fold expression able to compute the ratio member value of every base unit in the units type of the derived unit. Basically means, access the scalar value on the ::ratio::value, and multiply all the ones that are in the units member. But I've been never able to get the correct syntax for access the type elements one by one in a std::tuple, so I can get their value member – Alex Vergara Mar 30 '23 at 07:20
  • now it works perfect. With the previous one, I wasn't able to compile, since accessing with the `.` operator names wasn't really working. How can I explain better `Computations::ratio_product`, to remove your comment of still not clear and accept this? I think that you already got it, because is exactly what you are doing. If every derived unit has a `std::tuple` of `base unit` types, and every base unit has a `ratio` member defined, and every ratio has a `value` member, that holds the calculation of a power of base and exponent, I just need all the `value` member being multiplied! – Alex Vergara Mar 30 '23 at 08:26
  • Just a minor comment in addition. I am typically using Clang most of the time, and even with `std=c++20`, I still had to write `typename` for the dependant name in: `using collection_ratios = ratios::type`. So Clang didn't implemented yet the implicit typename C++20 extension – Alex Vergara Mar 30 '23 at 08:37
  • 1
    @AlexVergara I edited the answer to remove those comments. As for the `typename` requirement: clang 16 should have implicit typenames implemented. But yes, adding typename is best for compatibility for now. I added it to the answer as well. – Not a real meerkat Mar 30 '23 at 09:09
  • 1
    also note that I edited out an unnecessary lambda and static_assert. (They were reminiscent from a previous implementation) – Not a real meerkat Mar 30 '23 at 09:13
  • your answer it's simply perfect, at least for me. Thanks for your time – Alex Vergara Mar 30 '23 at 09:35