Curiously recurring template pattern

Curiously Recurring Template Pattern (CRTP) идиома языка C++, название которой можно примерно перевести как Любопытный рекурсивный шаблон или Любопытный повторяющийся шаблон, часто просто Рекурсивный шаблон, состоящая в том, что некоторый класс X является наследником от шаблона класса, использующего X как шаблонный параметр.

Используется и в Java — например, любой enum X является наследником от Enum<X>.

История

Эта техника была формализована в 1989 году под названием «F-bounded quantification». Название CRTP было предложено независимо Джеймсом Коплиеном[англ.] в 1995 году. Он обнаружил эту идиому в ранних шаблонных кодах на C++, а также в примерах, которые Тимоти Бадд[англ.] сделал для своего мультипарадигменного языка Leda[англ.]. Эта идиома иногда называется «Upside-Down Inheritance» (перевёрнутое наследование) из-за того, что она позволяет расширять иерархию классов за счёт подстановки других базовых классов.

Реализация от Microsoft в ATL была открыта независимо Яном Фалкином (англ. Jan Falkin) также в 1995 году. Он случайно унаследовал базовый класс от класса наследника. Кристиан Бомон (англ. Christian Beaumont), заметив этот код, решил, что он не может быть скомпилирован, но, выяснив, что может, решил положить эту ошибку в основу ATL и WTL.

Основная форма

// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
    // methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
    // ...
};

Статический полиморфизм

template <class T> 
struct Base
{
    void interface()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

struct Derived : Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

В примере выше функция Base<Derived>::interface() известна компилятору, хотя и объявлена перед объявлением структуры struct Derived. Тем не менее, эта функция не инстанцируется до момента фактического вызова, который должен произойти после объявления Derived.

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

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

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

Литература

  • David Abrahams, Aleksey Gurtovoy. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond. — Addison-Wesley, 2005. — ISBN 0-321-22725-5.

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.