4

I'm having a lot of trouble understanding the purpose of templates in ATL/WTL code.

When you look at WTL, you see code like:

template <class TBase>
class CEditT : public TBase
{
    ...
};

typedef CEditT<ATL::CWindow> CEdit;

Why is CEditT defined with a template base class?

In other words, in what scenario would CEditT<T> ever be instantiated where T is not CWindow?

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Maybe to accommodate a case where you want to provide your own Window implementation? – Praetorian Apr 23 '12 at 02:40
  • @Prætorian: How/why/when would you ever want/need/do that though? – user541686 Apr 23 '12 at 02:40
  • 2
    No idea :-). Maybe you have some very fancy skin implemented and want all your windows to have that skin. Also, that's not really CRTP, is it? For it to be [CRTP](https://secure.wikimedia.org/wikipedia/en/wiki/Curiously_recurring_template_pattern), `CEdit` would be `class CEdit : public Base { ... };` – Praetorian Apr 23 '12 at 02:41
  • @Prætorian: But that seems really weird for something like CEdit... also, I guess I was thinking of `CWindowImpl` when I wrote "CRTP". I'll remove that, thanks for pointing it out. – user541686 Apr 23 '12 at 02:51

4 Answers4

3

It's so that you can override methods in ATL::CWindow that are called by the ATL/WTL class. If there's something that you don't like in ATL::CWindow, you can derive a class from ATL::CWindow with overridden methods, and then pass along your new class as TBase.

For example, ATL::CWindow::CenterWindow for a long while had a bug where it did not properly account for multiple monitors, and I've seen people use this technique to override CenterWindow with a fixed implementation.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • +1 for a practical example, thanks. But one question: Isn't that already solvable with a templated *subclass*, though? (e.g. `FixedWindow` rather than `CEditT`) – user541686 Apr 24 '12 at 06:14
  • @Mehrdad: How would `FixedWindow` help if `CEdit` is the thing calling the offending function? Maybe I don't understand exactly what you mean. – jamesdlin Apr 24 '12 at 06:18
  • Oooh yeah it wouldn't, my bad. I was thinking of someone else calling the function, not the class itself. – user541686 Apr 24 '12 at 06:29
2

Suppose composition were used instead:

template <class TBase> class CEditT {
public:
  TBase base;
  ...
};

This is not very different from something like:

template <class ITEM> class ListNode {
public:
   ITEM item;
   ListNode<ITEM> *next;
   // ...
};

ListNode could instead inherit ITEM, like CEditT does with TBase, but the drawback would be that then ITEM could not be a basic type like int. On the other hand, a ListNode would then be a kind of ITEM, which could be useful. Furthermore, it would have access to any protected: parts of ITEM.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • I guess my question is, why doesn't it inherit directly from `CWindow` in the first place? – user541686 Apr 23 '12 at 02:51
  • Good question. That way it is not hard-coded to a particular window class implementation, just like `ListNode` isn't tied to a particular kind of `ITEM`. You could make your own window implementation, for instance, by customizing the standard one. Derive from it to make `MyWindow` and then you can instantiate `CEditT`. The question could be reversed: why should we tie a utility class to a particular target class when we can template it and target it to a *kind* of target class that just has the right interface? It's a paradigm. ;) – Kaz Apr 23 '12 at 02:56
  • In what scenario (practically speaking) would `CEditT` ever be instantiated where `T` is *not* `CWindow`? (Is there any known use case for this?) – user541686 Apr 23 '12 at 03:02
  • Hmm, good question. Even if there aren't, basically there is no good reaosn not to make `CEditT` be inconsistent with the framework. Someone somewhere is going to want `CEditT>` and be in for a rude surprise to find a monolithic `CEdit`. – Kaz Apr 23 '12 at 03:11
  • 1
    Here is a Yahoo groups posting on exactly this subject: http://tech.groups.yahoo.com/group/wtl/message/5500 – Kaz Apr 23 '12 at 03:12
1

It's so that it can take advantage of the Curiously Recurring Template Pattern. If you create a derived class of CEditT your definition would be class CMyEdit : public CEditT<CMyEdit>. By statically casting its this pointer to your class, CEditT can call your methods without having to use a vtable.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • When is that actually useful (for `CEditT` and the like)? – user541686 Apr 23 '12 at 03:12
  • @Mehrdad, a glance at the source for CEditT would probably answer that question. I don't have access to it right now or I'd do it myself. It's quite possible that it uses CRTP only to be consistent with all the other ATL classes. – Mark Ransom Apr 23 '12 at 03:16
  • This doesn't actually answer the question. It's not about CRTP. This question is about templatizing the *base* class, not the derived class to `static_cast` to. – jamesdlin Apr 24 '12 at 06:01
1

Why does everything use a template base class in ATL/WTL?

In nutshell, to achieve a "weird form of compile-time polymorphism" thanks to a design pattern (rather C++ idiom) one may call "upside-down inheritance" as technique to "specify the base class of a base class" in order to "allows you to insert your own classes into the class hierarchy" to achieve flexibility of specialising types "without hard-coding implementation to any particular derived class".

This all should become clear after reading the excellent article ATL and Upside-Down Inheritance - Understanding ATL's atypical design approach written by Jim Beveridge and published by Visual C++ Developers Journal in July, 1999. Here is link to full not paginated copy of the same article (also in the Wayback Machine).

mloskot
  • 37,086
  • 11
  • 109
  • 136