Как я могу использовать 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 составляют: