Практическое использование «любопытно повторяющегося шаблона шаблона»

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

Также посмотрите на это на практическом примере stackoverflow.com/questions/10374650/…

Ghita 29.04.2012 22:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
44
1
13 002
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

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

Какой процент прироста производительности и / или использования памяти вы получаете, кстати?

Steve Jessop 29.09.2008 20:31

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

moonshadow 29.09.2008 21:13

Я не понимаю, как это можно использовать. Polymorhpishm работает, используя указатель базового класса для вызова методов производного класса в соответствии с типом производного класса. Однако в коде CRTP вам по-прежнему нужно шаблон <имя-производного> class base {public: void impl () {static_cast <производное *> (this) -> impl (); }}; производный класс: public base <производный> {void impl () {/ * something * /}}; base <производное *> basePtr; Таким образом, вам все равно пришлось упомянуть производный класс в шаблоне, который побеждает полиморфный аспект, поскольку мне пришлось явно указать производный класс

ScaryAardvark 26.08.2010 20:59

Неработающей ссылке. Не ответил на вопрос.

ACyclic 15.01.2016 00:40

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

@Greg: можешь привести пример кода? до: [[класс B {виртуальный void f () = 0; void g () {.. f (); ..}}; class D: B {void f ();};]] после [[template <class Der> class B {void g () {static_cast <Der *> (this) -> f ();} }; class D: B <D> {void f ();};]] и т. д., но более детально, возможно, с более подходящими типами примеров.

Aaron 30.09.2008 02:49

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

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

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

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

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

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

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

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

the_drow 13.10.2010 17:57

Вы говорите о ковариантных типах возврата? Где переопределение виртуального метода может возвращать указатель (или ссылку) на класс, производный от исходного типа возвращаемого значения в базовом классе? Если так, то я в курсе. Но для меня это нечто иное, поскольку контракт с базовым классом определяется интерфейсом. Базовый класс не может получить доступ к методам (или любым другим идентификаторам), которые он еще не видел в каком-либо определении. В то время как в CRTP базовый класс может вызывать методы подкласса, который даже не был определен в точке вызова. Это происходит в момент создания.

QBziZ 10.12.2010 17:52

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

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