2

So,

I have the following template that multiplies two unit, e.g. velocity and time.

    //! The product of the TWO units
    template<template<typename> typename QuantityLhs, template<typename> typename QuantityRhs>
    struct Multiply
    {
        template<typename T>
        using type = units::unit<typename product_t<QuantityLhs<UNIT_LIB_DEFAULT_TYPE>, QuantityRhs<UNIT_LIB_DEFAULT_TYPE>>::conversion_factor, T>;
    };

This is called for example in the following way:

using AccuType = Multiply<Velocity, Time>::type<float>;

Issue

The above definition only accepts two template arguments, but I want an arbitrary number of them.

So what I wish to be able to write is something like

using AccuType = Multiply<Velocity, Time, Temperature, Density>::type<float>;

So my idea is to create a variadic template

    //! The product of the ANY number of units
    template<typename... Quantities>
    struct MultiplyMany
    {
        // Code
    };

Unfortunately, I don't know how to make it work. I have this idea that MultiplyMany would just somehow use a for loop or something to call the basic Multiply struct as many times as neccesary (iterating over template arguments).

Is that even possible?

3
  • 1
    It isn't clear why you need this. We multiply using the * symbol. That's a two argument operator, so a two-argument template works just fine. Commented Jun 13, 2024 at 8:32
  • 2
    Read about parameter pack expansion and fold expressions (the latter is useful for future metaprogramming). Commented Jun 13, 2024 at 8:34
  • i am a little confused about recursion. There is no recursion in your template, but you expected the solution to use recursion? Commented Jun 13, 2024 at 9:04

2 Answers 2

3

The old school method is to create both variadic and regular templates as specializations of the main template, and let the former call the later and itself recursively. Make sure there is no ambiguity between the two!

template<template<typename> typename... Quantities>
struct Multiply;

// The product of one unit is just that unit: one argument
template<template<typename> typename Quantity>
struct Multiply<Quantity>
{
    template<typename T>
    using type = Quantity<T>;
};

// The product of two OR MORE units: two or more arguments
template<template<typename> typename QuantityLhs, template<typename> typename QuantityRhs, template<typename> typename ... Rest>
struct Multiply<QuantityLhs, QuantityRhs, Rest...>
{
    template <typename T>
    using type0 = typename Multiply<QuantityRhs, Rest...>::type<T>;

    template<typename T>
    using type = units::unit<typename product_t<QuantityLhs<UNIT_LIB_DEFAULT_TYPE>, type0<UNIT_LIB_DEFAULT_TYPE>>::conversion_factor, T>; 
};

(Not tested due to lack of a minimal reproducible example)

(Actually a multiplication of zero arguments should be allowed, and result in an undimensioned quantity of 1, but I don't know how you handle those).

Sign up to request clarification or add additional context in comments.

2 Comments

Exactly what I needed! I only had to change using type0 = typename Multiply<QuantityRhs, Rest...>::type<T>; to using type0 = typename Multiply<QuantityRhs, Rest...>::template type<T>;.
The [mre] abbreviation seems to work only in comments, so I added the link.
2

You can just turn Quantity into variadic templates

template<template<typename> typename... Quantities>
struct Multiply
{
    template<typename T>
    using type = units::unit<
      typename product_t<Quantities<UNIT_LIB_DEFAULT_TYPE>...>::conversion_factor, T>;
};

using AccuType = Multiply<Velocity, Time, Temperature, Density>::type<float>;

1 Comment

This requires product_t to be a variadic template too

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.