C++ Academy · Урок

Когда использовать CRTP

Компромиссы и подводные камни

Урок 4 из 413 шагов

«Когда использовать CRTP» — бесплатный урок C++ Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Мощный, но требующий осторожности инструмент

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

Подходит: критические участки

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

Подходит: повторно используемое поведение

CRTP особенно хорошо подходит для добавления повторно используемого поведения (счётчиков, сравнений, сериализации), которое должно обращаться к конкретному типу.

#include <iostream>
#include <string>

template <typename T>
struct Serializable {
    void save() const { std::cout << static_cast<const T*>(this)->serialize() << "\n"; }
};

struct Config : Serializable<Config> {
    std::string serialize() const { return "config-data"; }
};

int main() {
    Config{}.save();
    return 0;
}

Недостаток: нет общего типа времени выполнения

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

  • Нужны полиморфные контейнеры? Используйте виртуальные функции

Недостаток: непонятные ошибки

Сообщения об ошибках CRTP могут быть длинными и запутанными, поскольку появляются глубоко внутри создания экземпляра шаблона. Опечатка в производном типе в Base<Wrong> не мешает компиляции, пока код не попытается вызвать отсутствующий метод.

Недостаток: неверный производный тип

Передача неправильного типа в базовый класс нарушает контракт static_cast и приводит к неопределённому поведению. Всегда записывайте Derived : Base<Derived>, используя совпадающие имена.

#include <iostream>

template <typename T>
struct Base {
    void go() { static_cast<T*>(this)->step(); }
};

struct Right : Base<Right> {
    void step() { std::cout << "ok\n"; }
};

int main() {
    Right{}.go();
    return 0;
}

Альтернатива: std::variant

Если у Вас есть фиксированный набор типов и нужна семантика значений, std::variant вместе с std::visit обеспечивает диспетчеризацию во время компиляции без наследования и часто оказывается понятнее CRTP.

#include <iostream>
#include <variant>

struct Add { int operator()(int a, int b) { return a + b; } };
struct Mul { int operator()(int a, int b) { return a * b; } };

int main() {
    std::variant<Add, Mul> op = Mul{};
    int r = std::visit([](auto f) { return f(3, 4); }, op);
    std::cout << r << "\n";
    return 0;
}

Альтернатива: концепты (C++20)

Для чистой проверки интерфейса во время компиляции концепты C++20 часто заменяют CRTP. Они ограничивают шаблоны и дают более понятные сообщения об ошибках без наследования.

Компромисс с удобством чтения

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

Что учитывать при сопровождении

CRTP тесно связывает базовый и производный классы. Изменение интерфейса класса-носителя может отразиться на каждой примеси. Чётко документируйте требуемые методы класса-носителя.

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

Контрольный список для принятия решения

Выбирайте CRTP, когда:

  • Вам нужна статическая диспетчеризация для повышения скорости
  • Вы добавляете поведение, обращающееся к конкретному типу
  • Вам не нужен общий базовый тип времени выполнения
  • Сложность оправдана

В противном случае рассмотрите виртуальные функции, вариантный тип или концепты.

Быстрая проверка

Выберите лучшую альтернативу, если нужен общий тип времени выполнения.

Повторение

Вы узнали, когда подходит CRTP.

  • Он отлично подходит для критических участков и повторно используемого поведения с обратным вызовом
  • Он плохо подходит, когда требуется общий тип времени выполнения
  • Остерегайтесь непонятных ошибок и использования неправильного типа
  • Альтернативы: виртуальные функции, вариантный тип, концепты C++20
Можно начать бесплатно

Изучай C++ с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
51
Уроки
203

Часто задаваемые вопросы

Урок «Когда использовать CRTP» бесплатный?

Да — полный текст урока «Когда использовать CRTP» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Когда использовать CRTP»?

Компромиссы и подводные камни Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Когда использовать CRTP»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Идиома CRTP
  2. Статический полиморфизм
  3. Миксины с CRTP
  4. Когда использовать CRTP
← Назад к C++ Academy