Шаблон "Дивно повторюваний шаблон шаблонів" (CRTP) є потужним інструментом, який дозволяє використовувати поліморфізм часу компіляції для підвищення ефективності, усуваючи накладні витрати на виклики віртуальних функцій. Це зменшує витрати, пов'язані з динамічною диспетчеризацією, що зазвичай потребує більше часу для виконання, а також полегшує роботу з об'єктами, зберігаючи їх поліморфізм.
У звичайному випадку, коли ми працюємо з поліморфними об'єктами, віртуальні методи можуть бути викликані таким чином:
#include
#include
#include
#include
struct Base { virtual void func() = 0; };
struct Derived1 : public Base { void func() override {} };
struct Derived2 : public Base { void func() override {} };
int main() {
std::vector<std::unique_ptr<Base>> lVec;
lVec.push_back(std::make_unique<Derived1>());
lVec.push_back(std::make_unique<Derived2>());
lVec.push_back(std::make_unique<Derived1>());
lVec[0]->func(); // Викликає Derived1::func
lVec[1]->func(); // Викликає Derived2::func
lVec[2]->func(); // Викликає Derived1::func
return 0;
}
Проте, якщо ми хочемо зберегти поліморфізм, але зменшити накладні витрати на динамічну диспетчеризацію, ми можемо застосувати шаблон CRTP. Для цього в C++17 використовуються два корисних інструменти: std::variant
та std::visit
.
#include
#include
template <typename T>
struct Base { void func() { static_cast<T*>(this)->func(); } };
struct Derived1 : public Base<Derived1> { void func() {} };
struct Derived2 : public Base<Derived2> { void func() {} };
auto visitor = [](auto& arg) { arg.func(); };
template <typename... Base>
using TVec = std::vector<std::variant<Base...>>;
int main() {
TVec<Derived1, Derived2> gVec {
Derived1{}, Derived2{}, Derived1{}
};
std::visit(visitor, gVec[0]); // Викликає Derived1::func
std::visit(visitor, gVec[1]); // Викликає Derived2::func
std::visit(visitor, gVec[2]); // Викликає Derived1::func
return 0;
}
У цьому прикладі, замість використання віртуальних функцій, ми використовуємо шаблон CRTP для досягнення того самого ефекту, при цьому зменшуючи накладні витрати на виклики віртуальних методів. Цей підхід дозволяє ефективно обробляти поліморфні об'єкти, зберігаючи швидкість виконання програми.
Якщо у вас є питання чи відгуки, не соромтеся звертатися через LinkedIn або Gmail.
Перекладено з: CRTP in the real world