Curiously Recurring Template

    技术2022-07-03  99

    By James O. Coplien

    The "Curiously Recurring Template" pattern comes from an article by JimCoplien: "The Column Without a Name: A Curiously Recurring Template Pattern," CppReport, February 1995.

    It occurs where a BaseClass is templated on the type of its derived class:

    template class Base;

    class Derived: public Base ;

    Such a base class has the following interesting properties:

    It has a unique qualified type for each derived class that inherits from it. It can reach into the NameSpace of its derived class. It requires derived classes define supporting methods. Strongly related to the concept of Interfaces, in other languages (for example theDeeLanguage.)

    (Please add more).

    Why would you want to use it? CRT classes are almost always used to factor out functionality that is similar for several classes but which needs to be partially specialized for those classes. Here are some examples:


    Base class that implements the infix operators for an arithmetic type in terms of +=, -=, *=, and /=:

    template struct ArithmeticType

    {

    T operator + (const T& other) const

    {

    T result(*this);

    result += other;

    return result;

    }

    // etc.

    };

    class Quaternion: public ArithmeticType

    {

    Quaternion& operator += (const Quaternion& other)

    {

    // etc.

    }

    };


    COM-like RunTimeTypeInformation implementation helper:

    struct Null { };

    template

    struct TypeList {

    typedef A head;

    typedef B rest;

    };

    template struct Inherits: public TL::head, public Inherits { };

    template<> struct Inherits { };

    template

    struct InterfaceFinder {

    static void* GetInterface(C* obj, const GUID& iid) {

    if (iid == TL::head::GetUuid())

    return static_cast (obj);

    return InterfaceFinder ::GetInterface(obj, iid);

    }

    };

    template struct InterfaceFinder {

    static void* GetInterface(C* obj, const GUID& iid) { return 0; }

    };

    template struct Implements: public Inherits {

    void *QueryInterface(const GUID& iid) {

    return InterfaceFinder ::GetInterface(static_cast (this), iid);

    }

    template bool QueryInterface(Intf*& result) {

    result = QueryInterface(Intf::GetUuid());

    return (result != 0);

    }

    };

    class Example: public Implements<

    Example,

    TypeList

    TypeList

    Null> > >

    {

    };

    // …

    Example* object;

    FirstInterface* first;

    if(object->QueryInterface(first))

    first->foo();

    (Okay, the syntax is a little awkward, but this could be radically improved with a suitable macro for creating typelists, c.f. AndreiAlexandrescu‘s work on the subject, described inModernCeePlusPlusDesign.)


    Counting the number of instances of a class:

    template class Counter {

    public:

    Counter() { ++count; }

    Counter(const Counter&) { ++count; }

    ~Counter() { –count; }

    static size_t howMany() { return count; }

    private:

    static size_t count;

    };

    template size_t Counter ::count = 0;

    // either embed a Counter to count objects

    class Widget {

    public:

    …..

    static size_t howMany() { return Counter ::howMany(); }

    private:

    …..

    Counter c;

    };

    // or inherit from Counter to count objects

    class Widget: private Counter {

    public:

    …..

    using Counter ::howMany; // make howMany public

    };

    from ScottMeyers, "Counting Objects in C++," C/C++ Users Journal, April 1998 (http://www.ddj.com/cpp/184403484).


    Isn’t this similar to MixIns in other languages? Basically, "given that type (a) implements interface (x), derive it into type (b) that implements interface (y) using the template code below". Your example above looks similar to corresponding RubyLanguage examples.

    Yes, the infix operators example is a Ruby mixin, especially when you consider that the Arithmetic Type template is publicly inherited. The COM-like helper example I don’t understand. The instance counter example can be done with difficulty in RubyLanguageby screwing around with Module# class_eval, but that’s not necessary. Instead, in idiomatic Ruby, instance counts are reported with ObjectSpace.each_object(Widget) {}. But beginning with version 1.1, ObjectSpace#each_object will be disabled by default inJayRuby for performance reasons (http://www.ruby-forum.com/topic/129606). —ElizabethWiethoff


    Is this the same as UpsideDownInheritance as used by the WindowsTemplateLibrary? I’m guessing "yes", since its basis, the ActiveTemplateLibrary, is referenced below.


    A similar idiom is used in JavaLanguage, but not often because Java generics are so limited.

    public class Base {

    public T m() { … }

    }

    public class Derived extends Base {

    }


    EiffelLanguage lets you use refer to the type of the derived class in the base class, so you don’t need this idiom.


    See GenerativeProgrammingBook; this idiom shows up a lot.

    Also described in Rector, Sells, ATL Internals (ISBN 0201695898 ) as "SimulatingDynamicBinding". See SimulatedDynamicBinding.

    Also described in Eckel, Allison, ThinkingInCeePlusPlus, vol. 2, ch. 5.

    Bottom of Form


    最新回复(0)