Практическое использование для "Любопытно повторяющегося шаблона"
Какие практические применения для " шаблонов любопытных повторений"? Обычно показанный пример " подсчитанного класса" не является убедительным примером для меня.
6 ответов
Имитация динамического связывания. Исключение затрат на вызовы виртуальных функций при сохранении некоторых иерархических преимуществ является огромным преимуществом для подсистем, где это может быть сделано в проекте, над которым я сейчас работаю.
Это также особенно полезно для миксинов (под которыми я подразумеваю классы, от которых вы наследуете для обеспечения функциональности), которые сами должны знать, над каким типом они работают (и, следовательно, должны быть шаблонами).
В Effective C++ Скотт Мейерс в качестве примера предоставляет шаблон класса NewHandlerSupport
Вы не могли бы сделать это без CRTP, так как вам нужно, чтобы шаблон NewHandlerSupport создавался отдельно, с отдельным статическим элементом данных для хранения текущего new_handler, для класса, который его использует.
Очевидно, что весь пример крайне не поточнобезопасен, но он иллюстрирует суть.
Мейерс предполагает, что CRTP можно рассматривать как "Сделай это для меня". Я бы сказал, что это обычно относится к любому миксину, и CRTP применяется в том случае, когда вам нужен шаблон миксина, а не просто класс миксина.
CRTP становится намного менее любопытным, если учесть, что тип подкласса, который передается суперклассу, необходим только во время расширения метода. Итак, все типы определены. Вам просто нужен шаблон для импорта символического типа подкласса в суперкласс, но это всего лишь предварительное объявление - поскольку все формальные типы параметров шаблона по определению - в отношении суперкласса.
Мы используем в несколько измененном виде, передавая подкласс в структуре типа признаков в суперкласс, чтобы позволить суперклассу возвращать объекты производного типа. Приложение представляет собой библиотеку для геометрического исчисления (точки, векторы, линии, прямоугольники), где все универсальные функции реализованы в суперклассе, а подкласс просто определяет определенный тип: CFltPoint наследуется от TGenPoint. Также CFltPoint существовал до TGenPoint, поэтому создание подклассов было естественным способом рефакторинга.
Для реального использования библиотеки CRTP, посмотрите ATL и WTL (wtl.sf.net). Он широко используется для полиморфизма во время компиляции.
Обычно он используется для полиморфно-подобных шаблонов, когда вам не нужно иметь возможность выбирать производный класс во время выполнения, только во время компиляции. Это может сэкономить накладные расходы на вызов виртуальной функции во время выполнения.
Это похоже на макрос C: используйте преимущество того, что макрос компилируется не во время определения, а во время использования.
#define CALL_THE_RIGHT_FOO foo()
файл А:
static void foo() {
// do file A thing
}
...
CALL_THE_RIGHT_FOO
...
файл А:
static void foo() {
// do file B thing
}
...
CALL_THE_RIGHT_FOO
...
Шаблон использования шаблона, который вы описываете, позволяет нам "вызывать правильный foo" в родительском шаблоне, откладывая определение того, что именно является правильным foo, до создания экземпляра шаблона. За исключением этого случая, это различие между ClassA:: foo и ClassB:: foo, основанное на значении T в Parent.