Вопрос или проблема
В следующем коде шаблон класса HANDLER
должен принимать один параметр шаблона F
и один параметр шаблона шаблона P<R, S>
. Базовый класс IMPLEMENTATION
зависит от параметров R
и S
. Способ, которым я объявляю шаблон класса HANDLER
, требует передачи аргументов шаблона F
, P
, R
и S
отдельно в списке шаблонов ‘HANDLER’ (смотрите конструктор класса BAR
). Разве нет способа передать шаблон класса ‘P<R, S>’ как один параметр в списке шаблонов ‘HANDLER’ (см. комментарий ниже конструктора класса ‘BAR’) и все равно рассматривать ‘R’ и ‘S’ как аргументы шаблона в классе ‘HANDLER’? Заранее спасибо, я все еще новичок в шаблонах C++.
template <typename R, typename S> class IMPLEMENTATION{
public:
};
template <typename F, template <typename, typename> class P, typename R, typename S> class HANDLER : public IMPLEMENTATION<R, S>{
private:
F object;
public:
HANDLER(const F& object) : object(object){}
};
template <typename R, typename S> class BAR{
private:
IMPLEMENTATION<R, S>* implementation;
public:
template <typename F> BAR(const F& object):implementation(new HANDLER<F, BAR ,R, S>(object)){}
/*template <typename F> BAR(const F& object):implementation(new HANDLER<F, BAR<R,S>>(object)){}*/
};
Ответ или решение
В вашем вопросе затрагивается передача шаблона класса в качестве шаблонного аргумента шаблона (template template argument) в C++. Вы правильно заметили, что в текущей реализации класса HANDLER
потребуется передавать параметры шаблона R
и S
отдельно. Однако существует способ обойти это ограничение, используя дополнительный шаблон.
Вы можете создать вспомогательный шаблон, который будет принимать ваши аргументы R
и S
и оборачивать их в один шаблонный параметр. Вот как это можно сделать:
template <typename R, typename S>
class Implementor {
public:
using type = IMPLEMENTATION<R, S>; // здесь создаем alias для удобства использования
};
template <typename F, template <typename, typename> class P, typename R, typename S>
class HANDLER : public Implementor<R, S>::type { // используем alias для доступа к IMPLEMENTATION
private:
F object;
public:
HANDLER(const F& object) : object(object) {}
};
template <typename R, typename S>
class BAR {
private:
typename Implementor<R, S>::type* implementation; // используем alias
public:
template <typename F>
BAR(const F& object)
: implementation(new HANDLER<F, BAR, R, S>(object)) {}
};
В этом коде мы создали вспомогательный класс Implementor
, который принимает R
и S
в качестве параметров и предоставляет type
, обозначающий IMPLEMENTATION<R, S>
. Теперь, когда мы объявляем HANDLER
, мы можем получить доступ к базовому классу, используя alias, что делает наш код более читаемым, но все еще требует, чтобы параметры R
и S
были указаны.
К сожалению, в текущем синтаксисе C++ нет способа передать P<R, S>
как единственный шаблонный аргумент, сохраняя возможность его параметризации. Тем не менее, данный подход с использованием вспомогательного шаблона позволяет минимизировать дублирование и упрощает отслеживание зависимостей между шаблонами.
Если вам нужно полностью скрыть детали реализации и передавать сложные зависимости как единое целое, вам, возможно, стоит рассмотреть другие подходы, например, использование комбинаций или утилитарных шаблнов для создания более сложных метапрограмм.