Практическое использование "Любопытно повторяющегося шаблона" - PullRequest
41 голосов
/ 29 сентября 2008

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

Ответы [ 6 ]

20 голосов
/ 29 сентября 2008

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

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

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

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

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

20 голосов
/ 29 сентября 2008

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

4 голосов
/ 29 сентября 2008

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

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

1 голос
/ 02 октября 2008

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

1 голос
/ 29 сентября 2008

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

0 голосов
/ 29 сентября 2008

Это похоже на макрос 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.

...