Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 22.  Bolt-ins


22.5. Simulated Compile-Time Polymorphism: Reverse Bolt-ins

This is another of those techniques, like the Schwarz counter (see section 11.2.3), that seems to get invented again and again. It also has several names. Let's have a look at it first, before we try to arbitrate between the different names. Consider the following template:



template <typename T>


struct RecursiveBoltIn


{


  void DoIt()


  {


    static_cast<T*>(this)->Do();


  }


};



RecursiveBoltIn is a not a bolt-in, because it doesn't derive from its parameterizing type. In a sense, though, it's a Reverse Bolt-in,[5] as we'll see. At first glance, it appears to be pretty simple and operates a constraint on its parameterizing type, requiring it to have a method Do(). Looking a little more closely, of course, we see that it's actually casting itself (this) to its parameterizing type. But it doesn't derive from the parameterizing type, so how can this work?

[5] In the absence of a better name, that's what I'm calling the concept.

As we know, the virtual function mechanism supports polymorphism by dereferencing the virtual function table pointer to access the virtual function table for the particular class [Lipp1996].[6] This occurs at run time. The lookup we see in RecursiveBoltIn, is performed in reverse bolt-ins at compile time, avoiding the cost of indirection at run time. For this reason, I like to call it Simulated Compile-time Polymorphism.

[6] This is not prescribed by the standard (see Chapters 7 and 8), but is the common implementation mechanism.

The first documentation of this technique that I'm aware of was by James Coplien [Lipp1998] in which he called it the Curiously Recurring Template Pattern (CRTP). It is used throughout Microsoft's Active Template Library (ATL), wherein it is called Simulated Dynamic Binding [Rect1999], and it is suggested in [Rect1999] that the ATL development team discovered it. The authors also suggest that this technique is not necessarily a supported part of the language, but I have not been able to locate a compiler that is unhappy with it as demonstrated in the two cases shown here; even Comeau in strict mode accepts it without question. (It's extremely useful, and so probably worth using despite the potential nonconformance.)

We can easily see how it works by looking at an example of a class that uses it.



class RecChild


  : public RecursiveBoltIn<RecChild>


{


public:


  void Do()


  {}


};



Now we see how the static_cast can work. RecChild derives publicly, and nonvirtually, from RecursiveBoltIn<RecChild>, so within the instantiation of RecursiveBoltIn<RecChild>, this can be statically cast to RecChild. Granted it seems more than a little strange, but it works, and is quite useful in applying a constraint to the parameterizing type of the bolt-in.

Note that the technique is not limited to functions; it is also possible to require a parameterizing derived class to provide nonfunction members, that is, member variables and enummembers.


      Previous section   Next section