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

The CRTP for interfaces -- not so useful?

80 views
Skip to first unread message

K. Frank

unread,
Feb 11, 2016, 12:28:58 PM2/11/16
to
Hello Group!

To follow up on my previous post, I have also seen
discussions where the CRTP (curiously recurring
template pattern) is used, as I understand it, to
define interfaces.

I suppose that this usage goes something like this:

template<typename D> struct Interface {
void doA() { static_cast<D*>(this)->implementationA(); }
void doB() { static_cast<D*>(this)->implementationB(); }
void doC() { static_cast<D*>(this)->implementationC(); }
};

Then a class that implements the interface could be:

struct D1 : public Interface<D1> {
void implementationA() { cout << "D1::implementationA" << endl; }
void implementationB() { cout << "D1::implementationB" << endl; }
void implementationC() { cout << "D1::implementationC" << endl; }
};

and could be used as follows:

template<typename T> struct UseInterface {
void doStuff() {
T t;
t.doA();
t.doB();
t.doC();
}
};

UseInterface<D1> ud;
ud.doStuff;

It's true that the class Interface serves to define the
interface to be implemented, but having to manually map
the interface to the implementation:

void doA() { static_cast<D*>(this)->implementationA(); }

seems annoying.

My preference in a case like this would be to just define
a class that "duck-types" the desired interface:

struct C {
void doA() { cout << "C::doA" << endl; }
void doB() { cout << "C::doB" << endl; }
void doC() { cout << "C::doC" << endl; }
};

and use it, e.g.:

UseInterface<C> uc;
uc.doStuff;

Am I missing anything about the benefits of using the
CRTP to define interfaces? If not, do you think that
using the CRTP as a place to define an interface is
worth the hassle?


Thanks.


K. Frank

Öö Tiib

unread,
Feb 13, 2016, 9:29:50 AM2/13/16
to
On Thursday, 11 February 2016 19:28:58 UTC+2, K. Frank wrote:
> Hello Group!
>
> To follow up on my previous post, I have also seen
> discussions where the CRTP (curiously recurring
> template pattern) is used, as I understand it, to
> define interfaces.
>

We often are in situation where base class needs to call functions of
derived class. Majority of other programming languages have chosen to
use virtual functions always in such a situation but C++ has CRTP.

CRTP provides two clear strengths, one is better efficiency and other
is faster feedback (compile time) about defects. It also provides
a major meta-weakness by increasing complexity of design since choice has
to be made design-time.

The choice between virtual functions or CRTP depends on if the
interrelations between run-time objects of resulting program are fixed
and known compile-time or not. On lot of cases these very likely are, on
few cases these certainly are not and on significant amount of cases it
can be uncertain design-time.

Therefore usage of virtual functions may be a premature pessimization
or usage of CRTP may be a premature optimization and if it happens
often then developer needs to gain skill in thinking about it first or
in refactoring between the two. ;)

>
> It's true that the class Interface serves to define the
> interface to be implemented, but having to manually map
> the interface to the implementation:
>
> void doA() { static_cast<D*>(this)->implementationA(); }
>
> seems annoying.

Unless I misunderstand you it looks rather little semantic
inconvenience that can be reduced with little mixin that provides
convenience helper overloads for that if you really bother.

void a() const { md().do_a(); }

Replace 'md()' with 'most_derived()' if abbreviations are forbidden
by codding standard.

Note that some developers ignore encapsulation and const-correctness
(use 'struct', everything non-const) and copy-paste code and that
results with wrong template arguments of CRTP:

struct foo : base<bar> { /* ... */ };

It is good idea to make that not to compile for example by making
something of 'base<bar>' non-accessible to 'foo' and idiomatically
it is private destructor:

template <typename T>
struct base
{
private:
~base() {}
friend T;
};

Note also that on lot of cases we want to do more things in implementation.
It may be for debugging purposes or because the gaps that derived class
fills do not match with external interface exactly 1:1:

void a() const { DBG("transaction a"); md().check(); md().do_a(); }
void b() { prepare_b(); md().do_b(); }


>
> My preference in a case like this would be to just define
> a class that "duck-types" the desired interface:
>
> struct C {
> void doA() { cout << "C::doA" << endl; }
> void doB() { cout << "C::doB" << endl; }
> void doC() { cout << "C::doC" << endl; }
> };
>
> and use it, e.g.:
>
> UseInterface<C> uc;
> uc.doStuff;

That is useful on lucky case when interface and gaps to fill match
exactly 1:1. The convenient external interface and gaps that derived
class is anticipated potentially to fill are usually rather different
and so your way results with violation of DRY (IOW several of
copy-paste-filled classes).

>
> Am I missing anything about the benefits of using the
> CRTP to define interfaces? If not, do you think that
> using the CRTP as a place to define an interface is
> worth the hassle?

I think that you consider the problem that CRTP solves as some sort of
close to 1:1 thin interface wrapper, and that is not anywhere frequent
case. You will get better idea what CRTP does by reading documentation
of libraries that use it in interface. There is large amount of
such libraries since the CRTP typically wins dynamic polymorphism in
performance and gives more compile-time diagnostics on case of misuse.

For example documentation of boost::iterator_facade explains it
quite well what is really typically expected to be going on:

|> iterator_facade and the operator implementations need to be able to
|> access the core member functions in the derived class. Making the
|> core member functions public would expose an implementation detail to
|> the user. The design used here ensures that implementation details
|> do not appear in the public interface of the derived iterator type.
http://www.boost.org/doc/libs/1_52_0/libs/iterator/doc/iterator_facade.html

Cholo Lennon

unread,
Feb 16, 2016, 7:58:22 AM2/16/16
to
If you want a real usage example of CRTP please see these 2 libraries
from Microsoft: ATL (Active template library) and WTL (Windows Template
Library). The last one is open source nowadays. They make heavy usage of
CRTP in order to implement static 'virtual' dispatching.

ATL: https://msdn.microsoft.com/en-us/library/3ax346b7.aspx
WTL: http://wtl.sourceforge.net/

Regards


--
Cholo Lennon
Bs.As.
ARG

K. Frank

unread,
Feb 16, 2016, 9:40:53 AM2/16/16
to
Hi Cholo!

On Tuesday, February 16, 2016 at 7:58:22 AM UTC-5, Cholo Lennon wrote:
> On 02/11/2016 02:28 PM, K. Frank wrote:
> > Hello Group!
> >
> > To follow up on my previous post, I have also seen
> > discussions where the CRTP (curiously recurring
> > template pattern) is used, as I understand it, to
> > define interfaces.
> > ...
> > Am I missing anything about the benefits of using the
> > CRTP to define interfaces? If not, do you think that
> > using the CRTP as a place to define an interface is
> > worth the hassle?
>
> If you want a real usage example of CRTP please see these 2 libraries
> from Microsoft: ATL (Active template library) and WTL (Windows Template
> Library). The last one is open source nowadays. They make heavy usage of
> CRTP in order to implement static 'virtual' dispatching.
>
> ATL: https://msdn.microsoft.com/en-us/library/3ax346b7.aspx
> WTL: http://wtl.sourceforge.net/

Could you give a short explanation of the usage of the
CRTP in ATL and/or WTL?

(Note, you've responded to my post about using the CRTP
to define "pure" interfaces, but I also posted a companion
question about the CRTP when there is "real code" in the
base class -- which I understand to be the more common
usage.)

I drilled down some into your ATL link. I got as far as

https://msdn.microsoft.com/en-us/library/f7c98h7e.aspx

... > ATL COM Desktop Components > Concepts Window Classes >
Implementing a Window > Message Handler Functions

but didn't see anything that was obviously relevant. (The
MSDN can be a bit inefficient to read at times.)

Do ATL and/or WTL go beyond the CRTP structure I outlined
in my two posts, or do they use those basic ideas, but in
an obviously more substantive concrete setting?

> Regards
>
> Cholo Lennon
> Bs.As.
> ARG


Thanks.

K. Frank

Alf P. Steinbach

unread,
Feb 16, 2016, 1:37:11 PM2/16/16
to
On 2/16/2016 3:40 PM, K. Frank wrote:
>
> Do ATL and/or WTL go beyond the CRTP structure I outlined
> in my two posts, or do they use those basic ideas, but in
> an obviously more substantive concrete setting?

There's nothing really interesting to find. WTL was based on ATL so
they're not really two different libraries. ATL used
base-class-as-template-parameter to define a most derived class that
implemented the COM IUnknown interface, that is, reference counting and
interface access by id.

I wouldn't really call it CRTP.

There's a bit of TP, but the the R, for Recurring, does not match the
designs in ATL/WTL.


Cheers & hth.,

- Alf

Cholo Lennon

unread,
Feb 16, 2016, 2:18:08 PM2/16/16
to
On 02/16/2016 03:36 PM, Alf P. Steinbach wrote:
> On 2/16/2016 3:40 PM, K. Frank wrote:
>>
>> Do ATL and/or WTL go beyond the CRTP structure I outlined
>> in my two posts, or do they use those basic ideas, but in
>> an obviously more substantive concrete setting?
>
> There's nothing really interesting to find. WTL was based on ATL so
> they're not really two different libraries.

Beyond its relationship, they are two different libraries (at least in
their final objective). ATS is for COM programming and WTL is for GUI
programming (ATL windowing is rudimentary compared with WTL. The last
one has abstractions for controls, dialogs, printings, ddx, support for
message maps, etc)


> ATL used
> base-class-as-template-parameter to define a most derived class that
> implemented the COM IUnknown interface, that is, reference counting and
> interface access by id.
>

> I wouldn't really call it CRTP.
>
> There's a bit of TP, but the the R, for Recurring, does not match the
> designs in ATL/WTL.
>

Well I disagree, just grep for "static_cast<T*>(this)" in both libraries...

Öö Tiib

unread,
Feb 16, 2016, 2:26:12 PM2/16/16
to
Not always but some class templates in ATL and majority of class
templates in WTL are CRTP and virtual functions are avoided. As contrast
in MFC all cases where base class of library needs to call methods of
derived class (by you or library) are handled with virtual functions.

CWindowImpl: https://msdn.microsoft.com/en-us/library/h4616bh2.aspx
IOleControlImpl: https://msdn.microsoft.com/en-us/library/a2w18t1x.aspx

K. Frank

unread,
Feb 16, 2016, 4:19:19 PM2/16/16
to
Hello All!

Thanks to everyone for their follow-up comments.

On Tuesday, February 16, 2016 at 2:26:12 PM UTC-5, Öö Tiib wrote:
> On Tuesday, 16 February 2016 20:37:11 UTC+2, Alf P. Steinbach wrote:
> > On 2/16/2016 3:40 PM, K. Frank wrote:
> > >
> > > Do ATL and/or WTL go beyond the CRTP structure I outlined
> > > in my two posts, or do they use those basic ideas, but in
> > > an obviously more substantive concrete setting?
> >
> > There's nothing really interesting to find. WTL was based on ATL so
> > they're not really two different libraries.
> > ...
> > I wouldn't really call it CRTP.
> > ...
>
> Not always but some class templates in ATL and majority of class
> templates in WTL are CRTP and virtual functions are avoided.
> ...
This is all very helpful.


Thanks again.


K. Frank
0 new messages