Изменение параметров шаблона шаблона в С++
Я хотел бы создать класс, который создает внутренние типы, которые являются вариантами типов, передаваемых в качестве параметров шаблона. Что-то вроде следующего, нефункционального примера:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
Base<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >
Так как Base
является полностью заданным типом, Base<RefinedType> refinedStorage;
не скомпилируется. Просто использование шаблона шаблона не будет работать, так как уточненный тип должен быть основан на вложенном параметре шаблона, а также на его базовом типе.
Как я могу реализовать этот шаблон создания типов на основе как полностью заданных, так и базовых типов параметра шаблона?
EDIT: Я хотел бы, чтобы это был композит с произвольной глубиной, с несколькими типами инжекторов, выполняющими каскад преобразований. Таким образом, передача параметра шаблона шаблона и базового параметра становится довольно громоздкой (особенно когда дело касается базового случая композита), и идеальное решение будет использовать более прямой синтаксис.
Ответы
Ответ 1
Я смог добиться этого, явно "повторно объявив" общий шаблон внутри себя:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
template<class T2>
using Recur = BaseClass<T2>;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename Base::template Recur<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >
Ответ 2
Вы можете ввести шаблон rebind
:
template <typename From, typename To>
struct rebind_1st;
template <template <typename... > class Cls, typename A0, typename... Args, typename To>
struct rebind_1st<Cls<A0, Args...>, To> {
using type = Cls<To, Args...>;
};
template <typename From, typename To>
using rebind_1st_t = typename rebind_1st<From, To>::type;
С помощью вашего Injector
станет:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType,
typename Base::InternalType> RefinedType;
rebind_1st_t<Base, RefinedType> refinedStorage;
};
Ответ 3
Нет необходимости в повторном шаблоне, что усложняет ситуацию. Просто введите шаблон шаблона:
template<typename>
struct Injector;
template<typename T, template<typename> class Base>
struct Injector<Base<T>>{
using refined_type = std::pair<typename Base::InternalType, typename Base::InternalType>;
Base<refined_type> refined_storage;
};
Вам нужно будет использовать специализированную специализацию, чтобы получить конкретный тип из шаблона шаблона.
Это используется так:
using injector_int = Injector<Base<int>>;
int main(){
injector_int i;
}
вот живой пример
Ответ 4
Вы можете предоставить внешний rebinder:
template <class Bound, class U>
struct rebinder;
template <template <class> class Binder, class B, class U>
struct rebinder<Binder<B>, U>
{
typedef Binder<U> type;
};
// Usage:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename rebinder<Base, RefinedType>::type refinedStorage;
};
[Живой пример]