Практическое применение “Странно повторяющегося шаблонного шаблона”

StackOverflow https://stackoverflow.com/questions/149336

Вопрос

Каковы некоторые практические применения этого "Любопытно Повторяющийся Шаблонный Шаблон"?Тот самый "подсчитанный класс" обычно приводимый пример просто не является для меня убедительным примером.

Это было полезно?

Решение

Имитируемая динамическая привязка.Отказ от затрат на вызовы виртуальных функций при сохранении некоторых иерархических преимуществ является огромной победой для подсистем, где это может быть сделано в проекте, над которым я сейчас работаю.

Другие советы

Это также особенно полезно для миксины (под которыми я подразумеваю классы, которые вы наследуете для обеспечения функциональности), которые сами должны знать, с каким типом они работают (и, следовательно, должны быть шаблонами).

В Эффективный C ++, Скотт Мейерс приводит в качестве примера шаблон класса NewHandlerSupport<T>.Это содержит статический метод для переопределения нового обработчика для определенного класса (таким же образом, что std::set_new_handler делает для оператора по умолчанию new), и оператор new, который использует обработчик.Чтобы предоставить обработчик для каждого типа, родительский класс должен знать, с каким типом он работает, поэтому это должен быть шаблон класса.Параметром шаблона является дочерний класс.

На самом деле вы не смогли бы сделать это без CRTP, поскольку вам нужно, чтобы шаблон NewHandlerSupport создавался отдельно, с отдельным статическим элементом данных для хранения текущего new_handler для каждого класса, который его использует.

Очевидно, что весь пример крайне не потокобезопасен, но он иллюстрирует суть.

Мейерс предполагает, что CRTP можно рассматривать как "Сделай это для меня".Я бы сказал, что это обычно имеет место для любого mixin, и CRTP применяется в случае, когда вам нужен шаблон mixin, а не просто класс mixin.

CRTP становится намного менее любопытным, если учесть, что тип подкласса, который передается суперклассу, необходим только во время расширения метода.Итак, тогда все типы определены.Вам просто нужен шаблон для импорта символьного типа подкласса в суперкласс, но это всего лишь прямое объявление - как и все формальные типы параметров шаблона по определению - в том, что касается суперкласса.

Мы используем в несколько измененной форме, передавая подкласс в структуре типа признаков суперклассу, чтобы суперкласс мог возвращать объекты производного типа.Приложение представляет собой библиотеку для геометрического анализа (точки, векторы, линии, прямоугольники), где вся общая функциональность реализована в суперклассе, а подкласс просто определяет определенный тип :CFltPoint наследуется от TGenPoint.Кроме того, CFltPoint существовал до TGenPoint, поэтому создание подклассов было естественным способом рефакторинга этого.

Обычно он используется для полиморфных шаблонов, где вам не нужно иметь возможность выбирать производный класс во время выполнения, только во время компиляции.Это может сэкономить накладные расходы на вызов виртуальной функции во время выполнения.

Для реального библиотечного использования CRTP посмотрите на ATL и WTL (wtl.sf.net).Он широко используется там для полиморфизма во время компиляции.

Это похоже на макрос C:воспользуйтесь тем преимуществом, что макрос компилируется не во время определения, а во время использования.

#define CALL_THE_RIGHT_FOO foo()

файл A:

static void foo() {
   // do file A thing
}
...
CALL_THE_RIGHT_FOO
...

файл A:

static void foo() {
   // do file B thing
}
...
CALL_THE_RIGHT_FOO
...

Шаблон использования шаблона, который вы описываете, позволяет нам "вызывать правильный foo" в родительском шаблоне, откладывая определение того, что именно является правильным foo, до создания экземпляра шаблона.За исключением этого случая, это различие между ClassA::foo и ClassB :: foo, основанное на значении T в Parent .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top