Як я можу використовувати CRTP в C ++, щоб уникнути накладних витрат на функції віртуального члена?
Як я можу використовувати CRTP в C ++, щоб уникнути накладних витрат на функції віртуального члена?
Відповіді:
Є два шляхи.
Перший - це статичне вказівку інтерфейсу для структури типів:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
Другий - уникаючи використання ідіоми посилання на базу або вказівник на базу, і виконуйте підключення під час компіляції. Використовуючи наведене вище визначення, ви можете мати функції шаблону, які виглядають так:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
Отже, поєднання визначення структури / інтерфейсу та вирахування типу компіляції у ваших функціях дозволяє виконувати статичне відправлення замість динамічного відправлення. У цьому суть статичного поліморфізму.
not_derived_from_base
це не походить від base
і не походить від base
...
Я сам шукав пристойних обговорень CRTP. Методи Тода Велдхуйзена для наукового C ++ - чудовий ресурс для цього (1.3) та багатьох інших передових методів, таких як шаблони виразів.
Крім того, я виявив, що ви можете прочитати більшість оригінальних статей Коплієна C ++ Gems у книгах Google. Можливо, це все ще так.
dynamic_cast
віртуальні методи.
Мені довелося шукати CRTP . Однак, зробивши це, я знайшов кілька матеріалів про статичний поліморфізм . Я підозрюю, що це відповідь на ваше запитання.
Виявляється, ATL досить широко використовує цей шаблон.
Ця відповідь у Вікіпедії містить усе необхідне. А саме:
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Хоча я не знаю, скільки насправді це купує вас. Накладні витрати на виклик віртуальної функції (звичайно, залежить від компілятора):
Хоча накладні витрати на статичний поліморфізм CRTP становлять: