Как разрешить вложенные шаблоны в C ++? - PullRequest
2 голосов
/ 30 января 2020

Я недавно задал вопрос об определении, указывает ли итератор на сложное значение во время компиляции, и получил ответ, который работает.

Вопрос здесь: Как я могу специализировать алгоритм для итераторов что указывает на сложные значения?

И решением был набор шаблонов, которые определяют, является ли один шаблон специализацией другого:

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

Это работает, но я очень трудно понять, как это работает. В частности, вложенное template в template сбивает меня с толку. Я также все еще плохо знаком с использованием шаблонов variadi c, и кажется странным иметь шаблон variadi c без предоставленного типа, например: <class...> вместо чего-то подобного <class... Args>.

Может кто-нибудь сломать этот шаблон и описать, как он решается?

1 Ответ

2 голосов
/ 30 января 2020

Следует учитывать, что существует три типа параметров шаблона:

1) типы

2) нетипы (или значения)

3) template-templates

Первому типу предшествует typename (или class)

template <typename T>
void foo (T const & t);

В предыдущем примере T - это тип, а t (a аргумент классической функции) - это значение типа T.

Второй тип параметра шаблона - это значения, которым предшествует тип значения (или auto, начиная с C ++ 17, для тип не указан)

template <int I>
void bar ()
 { std::cout << I << std::endl; }

В предыдущем примере параметр шаблона I представляет собой значение типа int.

Третий тип является наиболее сложным для объяснения.

Знаете ли вы (я полагаю), что std::vector<int> и std::vector<double> - это разные типы, но у них есть общий std::vector, класс шаблона.

Параметр шаблона-шаблона является параметр, который принимает std::vector, класс шаблона без аргументов.

Параметру шаблона-шаблона предшествует template ключевое слово, как в следующем примере

template <template <int> class C>
void baz ();

Параметр шаблона-шаблона C в предыдущем примере - это класс (или структура), для которого требуется единственный параметр шаблона int (значение).

Итак, если у вас есть класс

template <int I>
class getInt
 { };

, вы можете передать getInt в качестве параметра шаблона в baz()

baz<getInt>();

Теперь вы должны понимать code:

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

структура is_specialization - это структура шаблона, которая получает в качестве параметров шаблона тип (T) и шаблон-шаблон Template, которые принимают классы / структуры, получающие переменную c количество параметров шаблона типа.

Теперь у вас есть специализация is_specialization:

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

Эта специализация выбирается, когда первый параметр шаблона (Template<Args...>) является класс на основе второго (Template).

Пример: если вы создаете экземпляр

is_specialization<std::vector<int>, std::map>

, то выбирается основная версия (которая наследуется от std::false_type), поскольку std::vector<int> isn На основе std::map.

Но если вы создадите экземпляр

is_specialization<std::vector<int>, std::vector>

специализация (которая наследуется от std::true_type) выбрана потому, что std::vector<int> основана на std::vector.

...