Подтвердить что ты не робот

Параметры шаблона шаблона

Похоже, что шаблон шаблона шаблона меня убьет:(, lemme объясните, какое заблуждение я сделал в своем уме, что меня смущает:

template<class T>
class B {}; // A templated class

Вот еще один код:

template<template<class X> class Z = B> // problem is in this line for me
class BB{}; 

обратите внимание на строку в списке параметров шаблона BB, который:

template<class X> class Z = B

теперь то, что я хочу спросить, - это то, что останавливает С++ думать, что Z не является другим шаблоном класса Z i.e:

template<class X> class Z{
}

вместо того, чтобы думать, что класс Z является параметром шаблона.

Большое спасибо, я очень ценю любую помощь, чтобы удалить это заблуждение из моего ума)

4b9b3361

Ответ 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
}

Это будет довольно интенсивно, но, надеюсь, вы получите эту идею.

Помните: шаблоны шаблонов шаблонов не являются законными С++, поэтому вся эта функция поиска графа фактически не компилируется. Это просто "что, если?":)

Ответ 2

Это часть синтаксиса языка (который чудовищно и сильно зависит от контекста). Если template<class X> class Z встречается в списке параметров шаблона, то он интерпретируется как объявление формального параметра Z с видом (например, мета-тип; виды классифицируют типы таким же образом, как типы классифицируют значения). один аргумент класса ".