Рекурсивный шаблон C++ с переменным числом вариантов

Так,

У меня есть следующий шаблон, который умножает две единицы, например. скорость и время.

    //! 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 столько раз, сколько необходимо (перебирая аргументы шаблона).

Возможно ли это вообще?

Непонятно, зачем вам это нужно. Умножаем, используя символ *. Это оператор с двумя аргументами, поэтому шаблон с двумя аргументами работает нормально.

n. m. could be an AI 13.06.2024 10:32

Прочтите о расширении пакета параметров и выражениях свертки (последнее полезно для будущего метапрограммирования).

Weijun Zhou 13.06.2024 10:34

я немного запутался в рекурсии. В вашем шаблоне нет рекурсии, но вы ожидали, что решение будет использовать рекурсию?

463035818_is_not_an_ai 13.06.2024 11:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете просто превратить 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 тоже был вариационным шаблоном.

Caleth 13.06.2024 11:54
Ответ принят как подходящий

Метод старой школы заключается в создании как вариативных, так и обычных шаблонов как специализаций основного шаблона, и позволяет первому рекурсивно вызывать последний и сам себя. Убедитесь, что между ними нет двусмысленности!

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>;.

skrat 13.06.2024 11:32

Аббревиатура [mre], кажется, работает только в комментариях, поэтому я добавил ссылку.

wohlstad 13.06.2024 11:35

Другие вопросы по теме

Ошибка компиляции при использовании функций шаблона C++, которые принимают в качестве аргументов другие функции, которые принимают ссылки на указатели
Специализация шаблона вне встроенного пространства имен функции, определенной внутри встроенного пространства имен
Как вывести в шаблон имя текущего тега? (Тот, в котором мы находимся)
Может ли быть нарушено ODR, если определение шаблона создается только с разными параметрами?
Вывести параметры шаблона для параметра шаблона std::variant
Функция constexpr, которая продолжает умножать число до тех пор, пока оно не станет «достаточно большим»
Требуется ли для создания экземпляров шаблонов классов использовать только указатель или ссылку на них?
Как объявить конструктор с аргументами ровно nRow*nCol типа T?
Вывод шаблонной структуры в параметрах шаблонных функций
Шаблон для возврата вектора элементов