Так,
У меня есть следующий шаблон, который умножает две единицы, например. скорость и время.
//! 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>;
};
Это вызывается, например, следующим образом:
using AccuType = Multiply<Velocity, Time>::type<float>;
Приведенное выше определение принимает только два аргумента шаблона, но мне нужно произвольное их количество.
Итак, я хочу иметь возможность писать что-то вроде
using AccuType = Multiply<Velocity, Time, Temperature, Density>::type<float>;
Итак, моя идея — создать шаблон с переменным числом вариантов.
//! The product of the ANY number of units
template<typename... Quantities>
struct MultiplyMany
{
// Code
};
К сожалению, я не знаю, как заставить это работать. У меня есть идея, что MultiplyMany просто каким-то образом будет использовать цикл for или что-то в этом роде для вызова базовой структуры Multiply столько раз, сколько необходимо (перебирая аргументы шаблона).
Возможно ли это вообще?
Прочтите о расширении пакета параметров и выражениях свертки (последнее полезно для будущего метапрограммирования).
я немного запутался в рекурсии. В вашем шаблоне нет рекурсии, но вы ожидали, что решение будет использовать рекурсию?





Вы можете просто превратить Quantity в вариационные шаблоны.
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>;
Для этого необходимо, чтобы product_t тоже был вариационным шаблоном.
Метод старой школы заключается в создании как вариативных, так и обычных шаблонов как специализаций основного шаблона, и позволяет первому рекурсивно вызывать последний и сам себя. Убедитесь, что между ними нет двусмысленности!
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>;
};
(Не тестировалось из-за отсутствия минимально воспроизводимого примера)
(На самом деле должно быть разрешено умножение нулевых аргументов, что приведет к получению безразмерной величины 1, но я не знаю, как вы с этим справляетесь).
Именно то, что мне нужно! Мне нужно было всего лишь поменять using type0 = typename Multiply<QuantityRhs, Rest...>::type<T>; на using type0 = typename Multiply<QuantityRhs, Rest...>::template type<T>;.
Аббревиатура [mre], кажется, работает только в комментариях, поэтому я добавил ссылку.
Непонятно, зачем вам это нужно. Умножаем, используя символ
*. Это оператор с двумя аргументами, поэтому шаблон с двумя аргументами работает нормально.