Mankarse ответил на ваш вопрос, но я думал, что все равно буду звонить.
Параметры шаблона шаблона аналогичны параметрам обычного типа шаблона, за исключением того, что они соответствуют шаблонам, а не конкретным типам:
// Simple template class
template <typename Type>
class Foo
{
Type m_member;
};
// Template template class
template <template <typename Type> class TemplateType>
class Bar
{
TemplateType<int> m_ints;
};
Если это помогает, вы можете думать о них как о функциональных указателях.Нормальные функции просто принимают аргументы, как обычные шаблоны, просто принимают типы.Однако некоторые функции принимают указатели функций, которые принимают аргументы, так же как типы шаблонов шаблонов принимают шаблоны, которые принимают типы:
void foo(int x)
{
cout << x << endl;
}
void bar(void (*f)(int))
{
f(1);
f(2);
}
Чтобы ответить на ваш вопрос в комментариях: параметры шаблона шаблона невозможны.Однако причина, по которой они невозможны, состоит в том, что комитет по стандартизации решил, что шаблонных шаблонов было достаточно, вероятно, чтобы облегчить жизнь разработчикам компиляторов.При этом ничто не мешает комитету принять решение о том, что они возможны, и тогда подобные вещи будут действительными C ++:
template <template <template <typename> class> class TemplateTemplateType>
class Baz
{
TemplateTemplateType<Foo> m_foos;
};
typedef Baz<Bar> Example;
// Example would then have Bar<Foo> m_foos;
// which would have Foo<int> m_ints;
Опять же, вы можете увидеть параллели в указателях функций.
types <=> values
templates <=> functions of values
template templates <=> functions of functions of values
template template templates <=> functions of functions of functions of values
Функция, аналогичная Baz
, будет выглядеть следующим образом:
void baz(void (*g)(void (*f)(int)))
{
g(foo);
}
Где бы вы использовали шаблон шаблона шаблона?
Это довольно надуманно, но яМожно привести один пример: действительно универсальная библиотека поиска графов.
Два общих алгоритма поиска графа - это поиск по глубине (DFS) и поиск по ширине (BFS).Реализация двух алгоритмов идентична, за исключением одного: DFS использует стек узлов, тогда как BFS использует очередь.В идеале, мы бы просто написали алгоритм один раз со стеком / очередью в качестве аргумента.Кроме того, мы хотели бы указать контейнер реализации стека или очереди, чтобы мы могли сделать что-то вроде:
search<Stack, Vector>( myGraph ); // DFS
search<Queue, Deque>( myGraph ); // BFS
Но что такое стек или очередь?Ну, так же, как в STL, стек или очередь могут быть реализованы с любым типом контейнера: векторами, запросами, списками и т. Д., А также могут быть стеками любого типа элемента, поэтому наши стеки или очереди будут иметь интерфейс:
Stack<Vector, int> // stack of ints, using a vector implementation
Queue<Deque, bool> // queue of bools, using a deque implementation
Но Vector
и Deque
сами по себе являются типами шаблонов!
Итак, наконец, наш Stack
будет шаблоном шаблона:
template <template <typename> class Storage, typename Element>
struct Stack
{
void push(const Element& e) { m_storage.push_back(e); }
void pop() { m_storage.pop_back(); }
Storage<Element> m_storage;
};
Итогда наш search
алгоритм должен быть шаблоном шаблона!
template <template <template <typename> class, typename> class DataStructure,
template <typename> class Storage,
typename Graph>
void search(const Graph& g)
{
DataStructure<Storage, typename Graph::Node> data;
// do algorithm
}
Это было бы довольно интенсивно, но, надеюсь, вы поняли идею.
Помните: шаблоны шаблонов недопустимый C ++, поэтому весь этот поиск по графу не будет компилироваться.Это просто "что если?":)