Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The CRTP -- code reuse and customization?

20 views
Skip to first unread message

K. Frank

unread,
Feb 11, 2016, 12:18:27 PM2/11/16
to
I am playing around with the CRTP (curiously recurring
template pattern) to get a feel for when it might be
useful in practice.

Does my simple example below show the full structure
of the CRTP, or am I missing an important part of the
picture?

(As I understand it, you can use the CRTP instead of a
similar virtual-function design, avoiding the virtual-
function overhead at the cost of giving up run-time
polymorphism.)

My simple example uses the CRTP for reuse and customization
of code. The idea is that Base::doStuff() implements
non-trivial logic (trivial in the example) that CRTP-derived
classes can reuse and customize by overriding doA(), etc.

template<typename D> struct Base {
void doStuff() {
static_cast<D*>(this)->doA();
static_cast<D*>(this)->doB();
static_cast<D*>(this)->doC();
}
// no default for doA
void doB() { cout << "Base::doB" << endl; } // default doB
void doC() { cout << "Base::doC" << endl; } // default doC
};

struct D1 : public Base<D1> {
void doA() { cout << "D1::doA" << endl; } // implement doA
void doB() { cout << "D1::doB" << endl; } // override doB
// use default doC from Base
};

Is this the basic structure and purpose of the CRTP?


Thanks.


K. Frank

Alf P. Steinbach

unread,
Feb 11, 2016, 12:56:37 PM2/11/16
to
This structure, where a derived class can customize part of a procedure,
is called the template pattern.

It's one way to use CRTP.

In your next posting you describe another way to use CRTP, namely to
define a non-virtual interface.

The original use of CRTP, by Barton and Nackman in their 1994 book
“Scientific and Engineering C++” (if I recall this correctly), was to
inherit in a mixin class. E.g. I use CRTP to inherit in relational
operators defined in terms of the derived class' `compare` function.
This relied on a subtle rule, called "friend name injection", that have
since been removed because the Baron-Nackman trick was its only use;
instead a friend function defined inline in a class is now found via
argument dependent lookup, so that the trick still works.

Summing up, the CRTP technique is a basic tool that can be used for many
different things.

Some people think that using CRTP for compile time polyorphism will
always result in code bloat, the compiler generating umpteen slightly
different machine code pieces for the same little source snippet. And so
it was in early pre-standard C++. But when I measured this around the
year 2000 somewhere, for at least some simple small programs the
run-time polymorphism yielded less code than using virtual functions.


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Feb 11, 2016, 1:00:37 PM2/11/16
to
On 2/11/2016 6:56 PM, Alf P. Steinbach wrote:
> it was in early pre-standard C++. But when I measured this around the
> year 2000 somewhere, for at least some simple small programs the
> run-time polymorphism yielded less code than using virtual functions.
^^^^^^^^

“compile time”

Also, “has” instead of “have” somewhere earlier.

Why don't Usenet clients offer a preview, with such errors indicated,
when one clicks the “Send” button?


Just wondering,

- Alf




Paavo Helde

unread,
Feb 11, 2016, 1:21:59 PM2/11/16
to
On 11.02.2016 20:00, Alf P. Steinbach wrote:
> On 2/11/2016 6:56 PM, Alf P. Steinbach wrote:
>> run-time polymorphism yielded less code than using virtual functions.
> ^^^^^^^^
>
> “compile time”
>
> Why don't Usenet clients offer a preview, with such errors indicated,
> when one clicks the “Send” button?

If the usenet client is smart enough to know what is correct, "compile
time" or "run time", then I suspect it won't need your help any more and
can answer the posts by itself ;-)


K. Frank

unread,
Feb 11, 2016, 2:40:07 PM2/11/16
to
Hi Alf!

On Thursday, February 11, 2016 at 12:56:37 PM UTC-5, Alf P. Steinbach wrote:
> On 2/11/2016 6:18 PM, K. Frank wrote:
> > I am playing around with the CRTP (curiously recurring
> > template pattern) ...
> > ...
> > template<typename D> struct Base {
> > void doStuff() {
> > static_cast<D*>(this)->doA();
> > static_cast<D*>(this)->doB();
> > static_cast<D*>(this)->doC();
> > }
> > // no default for doA
> > void doB() { cout << "Base::doB" << endl; } // default doB
> > void doC() { cout << "Base::doC" << endl; } // default doC
> > };
> >
> > struct D1 : public Base<D1> {
> > void doA() { cout << "D1::doA" << endl; } // implement doA
> > void doB() { cout << "D1::doB" << endl; } // override doB
> > // use default doC from Base
> > };
> >
> > Is this the basic structure and purpose of the CRTP?
>
> This structure, where a derived class can customize part of a procedure,
> is called the template pattern.
>
> It's one way to use CRTP.
> ...
> The original use of CRTP, by Barton and Nackman in their 1994 book
> "Scientific and Engineering C++" (if I recall this correctly), was to
> inherit in a mixin class. E.g. I use CRTP to inherit in relational
> operators defined in terms of the derived class' `compare` function.

I've read through the Barton and Nackman CRTP (as described by
Coplien). Would you describe it as fundamentally structurally
different than my example, or is it used for a conceptually
different purpose, but is structurally the same?

I would draw the parallel as follows:

operator= (in the CRTP base class) implements the "non-trivial"
logic of defining "equals" in terms of "less than." The derived
class "customizes" this behavior by implementing operator<.

Is there more to the Barton-Nackman machinery than meets my eye?

> This relied on a subtle rule, called "friend name injection", that have
> since been removed because the Barton-Nackman trick was its only use;
> instead a friend function defined inline in a class is now found via
> argument dependent lookup, so that the trick still works.

I assume that "friend name injection" and ADL come into play
because we're defining operators (where ADL is most useful),
but, other than this syntactic issue, we're just working with
otherwise regular member and/or friend functions. Or am I missing
something important about the Barton-Nackman structure.?

> Summing up, the CRTP technique is a basic tool that can be used for many
> different things.
> ...
>
> Cheers & hth.,
>
> - Alf


Thanks.


K. Frank

Alf P. Steinbach

unread,
Feb 11, 2016, 3:05:09 PM2/11/16
to
Well, OK, it's a matter of degrees.

In your example small parts of an operation can be customized by a
derived class. This is the template pattern. The parts typically have
few constraints imposed on them. For example, the `doStuff` operation
can be a general way to handle failures, where the customizable parts
are, first, some arbitrary main operation to do, let's call that A, and
second, a part that handles failure of A, let's call that B, that is
constrained to either itself fail, or else have changed the state
sufficiently (e.g. by just waiting a little) to let A possibly succeed
if tried again, and C, a cap on the number of retries.

For comparison, in the Barton-Nackman trick, as used for relational
operators, a number of operations are defined in terms of a single
derived class operation. Or a very small number of such. The derived
class operation is tightly constrained, e.g., that it must implement a
strict ordering.

Conceptually, with the template pattern there is a single algorithm for
something, that has customization points so that you can /change/ it.

While with a mixin class, conceptually you don't change anything, it
just adds capabilities to your class, based on its it-will-have-that
anyway basic functionality and possibly functionality elsewhere.

But you're right that there's much overlapping.

It's like, `goto` can be used to implement a `while` loop or a `do`
loop, but then, a `while` can be implemented in terms of `do`, and vice
versa. They're just used for different things. With different conceptual
pictures and slightly different associated guarantees.


>> This relied on a subtle rule, called "friend name injection", that have
>> since been removed because the Barton-Nackman trick was its only use;
>> instead a friend function defined inline in a class is now found via
>> argument dependent lookup, so that the trick still works.
>
> I assume that "friend name injection" and ADL come into play
> because we're defining operators (where ADL is most useful),
> but, other than this syntactic issue, we're just working with
> otherwise regular member and/or friend functions. Or am I missing
> something important about the Barton-Nackman structure.?

It's having e.g.

friend
auto operator<( Derived const& a, Derived const& b )
-> bool
{ return compare( a, b ) < 0; }

directly in the CRTP base class.

It's not a member function, yet must be found and invoked when client
code has `a < b` with objects of the derived class.

So it's /like/ placing this definition at namespace scope, yet it's
inherited in, which you can't do for a real namespace scope function.


Cheers & hth., possibly others will chime in with better explanations!,

- Alf

0 new messages