Дивно рекурсивний шаблон

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

Дивно рекурсивний шаблон (англ. curiously recurring template pattern (CRTP)) — це підхід в C++, в якому клас X є похідним від шаблону класу, інстанційованого із використанням самого X в якості шаблонного аргументу. Ім'я цього підходу було винайдене Джимом Копліном,[1], який розглянув його в одному з найперших шаблонних кодів на C++.

Загальна форма[ред.ред. код]

template <typename T>
struct base
{
    // ...
};
struct derived : base<derived>
{
    // ...
};

Цей підхід можна використати для статичного поліморфізму, а також в деяких інших техніках метапрограмування як описано Андрієм Александреску в його книзі — Сучасне проектування на C++.[2]

Статичний поліморфізм[ред.ред. код]

#include <iostream>
using namespace std;
 
template<typename Derived>
struct Base
{
    void foo()
    {
        static_cast<Derived*>(this)->foo();
    }
};
 
struct A : Base<A>
{
    void foo()
    {
        cout << "A::foo();" << endl;
    }
};
 
struct B : Base<B>
{
    void foo()
    {
        cout << "B::foo();" << endl;
    }
};
 
template<typename T>
void bar(Base<T>& base)
{
    base.foo();
}
 
int main()
{
    A a;
    B b;
    bar(a);
    bar(b); 
    return 0;
}

Цей підхід дає ефект подібний до використання віртуальних функцій, без ціни (і деякої гнучкості) динамічного поліморфізму. Це використання CRTP дехто називає "симулювання динамічного зв'язування".[3] Цей підхід широко використовується в Windows бібліотеках ATL і WTL.

Лічильник об'єктів[ред.ред. код]

Головною ціллю лічильника об'єктів — отримання статистики створення й руйнування об'єктів даного класу. Це можна легко виправити із використанням CRTP:

template <typename T>
struct counter
{
    static int objects_created;
    static int objects_alive;
 
    counter()
    {
        ++objects_created;
        ++objects_alive;
    }
protected:
    ~counter()
    {
        --objects_alive;
    }
};
template <typename T> int counter<T>::objects_created( 0 );
template <typename T> int counter<T>::objects_alive( 0 );
 
class X : counter<X>
{
    // ...
};
 
class Y : counter<Y>
{
    // ...
};

Примітки[ред.ред. код]

  1. Coplien, James O. (1995, February). «Curiously Recurring Template Patterns». C++ Report. с. 24–27. 
  2. Alexandrescu, Andrei (2001). Сучасне проектування на C++: Generic Programming and Design Patterns Applied. Addison-Wesley. ISBN 0-201-70431-5. 
  3. «Simulated Dynamic Binding». 2003-05-07. Архів оригіналу за 2013-07-21. Процитовано 2012-01-13.