您的位置:首页 > 移动开发 > Objective-C

递归模板模式--The curiously recurring template pattern

2008-07-28 10:15 483 查看

1  The curiously recurring template pattern

1.1 General form

// The Curiously Recurring Template Pattern (CRTP)
template <typename derived>struct base{    // ...};struct derived : base<derived>{    // ...};

Some use cases for this pattern are static polymorphism, and other
metaprogramming techniques such as those described by Alexandrescu in Modern C++ Design [2].

1.2
[edit] Static polymorphism

Typically, the base class template will take advantage of
the fact that member function bodies (definitions) are not instantiated until
long after their declarations, and will use members of the derived class within
its own member functions, via the use of a
static_cast
, or simply
a cast e.g.:

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();};

This technique achieves a similar effect to the use of
virtual functions, without the costs (and some flexibility) of dynamic
polymorphism. This particular use of the CRTP has been called "simulated
dynamic binding" by some[3]. This pattern is used extensively in the Windows ATL and WTL libraries.

To elaborate on the above example, consider a base class
with no virtual functions. Whenever the base class calls another member
function, it will always call its own base class functions. When we inherit
from this class, a derived class, we inherit all the member variables and
member functions that weren't overridden (no constructors or destructors, of
course, either). If the derived class calls an inherited function that then
calls another member function, that function will never call any derived or
overridden member functions in the derived class. As a result of this behavior,
most C++ programmers define member functions as virtual to avoid this problem.

However, if base class member functions use the CRTP
pattern for all member function calls, the overridden functions in the derived
class will get selected at compile time. This effectively emulates the virtual
function call system at compile time without the costs in size or function call
overhead (VTBL
structures, and method lookups, multiple-inheritance VTBL machinery) and the
slight disadvantage of not being able to do this choice at runtime.

1.3 [edit] Object counter

The main purpose of an object counter is retrieving
statistics of object creation and destruction for a given class. This can be
easily solved using CRTP:

template <typename T>
struct counter{    counter()    {        objects_created++;        objects_alive++;    }     virtual ~counter()    {        --objects_alive;    }    static int objects_created;    static int 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>{    // ...};

Each time an object of class
X
is created, the
constructor of
counter<X>
is called, incrementing both the
created and alive count. Each time an object of class
X
is
destroyed, the alive count is decremented. In this example, none of the
functionality in the template uses the template parameter, and it is only used
as a way of creating different static counters for different classes. Remember
that each instantiation of a template with a type argument is a class of
itself, and thus the static counter attributes in the
counter

template are different offering separated counters for
X
and
Y

classes.

 

int main() {

CountedClass a;

cout << CountedClass::getCount() << endl; // 1

CountedClass b;

cout << CountedClass::getCount() << endl; // 2

CountedClass2 c;

cout << CountedClass2::getCount() << endl; // 1 (!)

} ///:~

 

Each derived class derives from a unique base class that is determined by
using itself (the derived class) as a template parameter! This may seem like a
circular definition, and it would be, had any base class members used the
template argument in a computation. Since no data members of Counted are
dependent on T, the size of Counted (which is zero!) is known
when the template is parsed. So it doesn t matter which argument is used to
instantiate Counted because the size is always the same. Any derivation
from an instance of Counted can be completed when it is parsed, and
there is no recursion. Since each base class is unique, it has its own static
data, thus constituting a handy technique for adding counting to any class
whatsoever. Jim Coplien was the first to mention this interesting derivation
idiom in print, which he cited in an article, entitled Curiously Recurring
Template Patterns.

 

1.4
[edit] In other languages

The CRTP makes an appearance in the Java
programming language standard library where the Enum
class is defined as
Enum<T extends Enum<T>>
. Java
programmers use the CRTP in practice when they write a comparable class:
class
X implements Comparable<X>
.

1.5 [edit] See also

Barton-Nackman trick

1.6 [edit] References

^ Coplien, James O. (1995, February). "Curiously Recurring
Template Patterns". C++ Report: 24–27. 

^ Andrei Alexandrescu: Modern C++ Design: Generic Programming and
Design Patterns Applied
, Addison-Wesley, ISBN
3-8266-1347-3

^ http://www.pnotepad.org/devlog/archives/000083.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息