Ответ 1
Манкарсе ответил на ваш вопрос, но я думал, что все равно перезвоню.
Параметры шаблона шаблона похожи на обычные параметры шаблона шаблона, за исключением того, что они соответствуют шаблонам вместо конкретных типов:
// 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);
}
Чтобы ответить на ваш вопрос в комментариях: параметры шаблона шаблона шаблона невозможны. Однако причина, по которой они невозможны, заключается только в том, что комитет по стандартизации решил, что шаблоны шаблонов были достаточными, вероятно, для облегчения жизни для разработчиков компилятора. Тем не менее, ничто не мешает комитету решить, что они возможны, тогда подобные вещи будут действительны С++:
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, стек или очередь могут быть реализованы с любым видом контейнера: векторами, deques, списками и т.д., А также могут быть стеками любого типа элемента, поэтому наши стеки или очереди будут иметь интерфейс:
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
}
Это будет довольно интенсивно, но, надеюсь, вы получите эту идею.
Помните: шаблоны шаблонов шаблонов не являются законными С++, поэтому вся эта функция поиска графа фактически не компилируется. Это просто "что, если?":)