2015-07-13 5 views
10

Я хотел бы создать класс, который создает внутренние типы, которые являются вариантами типов, переданных в качестве параметров шаблона. Что-то вроде следующего, нефункциональных например:Изменение параметров шаблона шаблона в C++

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

Почему вы не сделать шаблон параметр шаблона _и_ параметра T, который будет использоваться как 'Injector '? – Petr

+0

@Petr Я подумал об этом, но в идеале я хотел бы установить его как композит с произвольной глубиной с изменениями, распространяющимися через несколько слоев. –

ответ

10

я смог добиться этого явно 'повторно объявить' общий шаблон внутри себя:

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> > 
+4

FWIW, это как ['std :: allocator'] (http://en.cppreference.com/w/cpp/memory/allocator) делает это (за исключением того, что он называет его' rebind', и его внутренний typedef вызывается 'other'). – Barry

4

Вы можете обеспечить внешний Ребиндера:

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

[Live example]

+0

Ха, я только заметил, что у нас есть тот же ответ. Er. +1 Я думаю :) – Barry

8

Вы может ввести шаблон 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; 
}; 
5

Там нет необходимости для шаблона пересвязывание, что чрезмерное усложняет ситуацию. Просто введите шаблон шаблона:

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

here's a live example

+0

*, который просто добавляет к времени компиляции * => не так ли? Я имею в виду, есть ли измеримое влияние на производительность? Это, по-видимому, необоснованное утверждение, которое отвлекает от основного момента: ваше решение * проще *, чем повторение, а простое лучше (в общем). –

+0

@ MatthieuM. время компиляции не влияет на производительность, поэтому я не совсем уверен, что вы имеете в виду. Но да, добавление в другой класс для перезаписи должно теоретически заставлять компилятор делать больше работы; даже если только при анализе дополнительного источника. – CoffeeandCode

+0

Я говорил о производительности компиляции :) Это просто, что, насколько мне известно, этот комментарий совершенно не нужен и может отвлекать от основной точки (самого ответа). –

Смежные вопросы