tags:

views:

71

answers:

4

There's a bunch of special macros that MFC uses when creating dialogs, and in my quick tests I'm getting weird errors trying to compile a template dialog class. Is this likely to be a big pain to achieve?

Here's what I tried:

MyDlg.h

template <class W>
class CMyDlg : public CDialog
{
    typedef CDialog super;
    DECLARE_DYNAMIC(CMyDlg <W>)

public:
    CMyDlg (CWnd* pParent);   // standard constructor
    virtual ~CMyDlg ();

// Dialog Data
    enum { IDD = IDD_MYDLG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    DECLARE_MESSAGE_MAP()

private:
    W *m_pWidget; //W will always be a CDialog
};



IMPLEMENT_DYNAMIC(CMyDlg<W>, super) <-------------------

template <class W>
CMyDlg<W>::CMyDlg(CWnd* pParent)
    : super(CMyDlg::IDD, pParent)
{
  m_pWidget = new W(this);
}

I get a whole bunch of errors but main one appears to be:

error C2955: 'CMyDlg' : use of class template requires template argument list

I tried using some specialised template versions of macros but it doesn't help much, other errors change but this one remains. Note my code is all in one file, since C++ templates don't like .h/.cpp like normal.

I'm assuming someone must have done this in the past, possibly creating custom versions of macros, but I can't find it by searching, since 'template' has other meanings.

A: 

I haven't done this for a dialog, only for some custom controls, but I see no reason why It wouldn't work.
I know that there's at least a template version for defining message maps, BEGIN_TEMPLATE_MESSAGE_MAP. Check out http://msdn.microsoft.com/en-us/library/aa991537(VS.80).aspx

humbagumba
+2  A: 

You may have other problems as well, but one thing has got to be your use of super. That's a java thing not a C++ thing. Instead of super you need to use CDialog.

After looking into IMPLEMENT_DYNAMIC the macro definition is not compatible with templates, it doesn't use the template <class T> syntax before the function definitions. What you need to do is define derived class specializations of your template and then use the macro on them. So you could do this:

class MyDlgA : public CMyDlg<A>
{
};

IMPLEMENT_DYNAMIC(MyDlgA, CDialog);

And then do that for all specializations that you want. If that's not feasible, look at the macro and make your own templatized version of it.

Edit: Following up on my comment, you could make a macro like this:

#define INSTANTIATE_DLG_TEMPLATE(T)  \
class MyDlg##T : public CMyDlg<T>    \
{                                    \
};                                   \
                                     \
IMPLEMENT_DYNAMIC(MyDlg##T, CDialog);

And then just use this wherever you would normally have defined the template specialization in a header file with a typedef.

bshields
I define this myself for convenience. Works well (and by the way MSVC has a __super keyword)
John
Ok if that's the way you want to do it, I would still try it without it if you're having compile errors to make sure it's not playing a part. But the second part of my answer is definitely causing you problems as well.
bshields
Hmm, specialization would kind of undo the whole point of templates. I can look at the macros but the problem is there are quite a few that all call each other... yuck.
John
Well you have to specialize at some point. Note that this doesn't have to occur in the same header that defines your CMyDlg template class. The only thing that's more cumbersome here than the normal case is the fact that you need to make an empty derived class instead of just a typedef since you need to be able to define methods for the class using the IMPLEMENT_DYNAMIC macro. You know you could make your own macro that defined the empty derived class and invoked the IMPLEMENT_DYNAMIC macro and you could use that wherever you would normally have put a typedef for a template instantiation.
bshields
Interesting idea, I'll bear it in mind although my preference is to get a template-friendly set of macros if possible.
John
A: 

The C++ language doesn't hold you to use certain patterns in programming. As long as the template instantiation is valid as a code you can do whatever you want with that code.

Simply put: the language syntax represents no restriction, make sure you write valid code.

Iulian Şerbănoiu
Yes but if the utility code in MFC can't handle the templates, things break down.
John
A: 

Here's a working solution, though ugly... I didn't get round to rewriting as a macro after expanding the existing one and fixing for templates:

//Template-enabled expansion of IMPLEMENT_DYNAMIC(CMyDlg,super)
template <class W> CRuntimeClass* PASCAL CMyDlg<W>::_GetBaseClass(){ return RUNTIME_CLASS(super); }
template <class W> AFX_COMDAT const CRuntimeClass CMyDlg<W>::CMyDlg= {
        "CMyDlg", sizeof(CMyDlg<W>), 0xFFFF, NULL,&CMyDlg<W>::_GetBaseClass, NULL, NULL };
template <class W> CRuntimeClass* PASCAL CMyDlg<W>::GetThisClass()  { return _RUNTIME_CLASS(CMyDlg); }
template <class W> CRuntimeClass* CMyDlg<W>::GetRuntimeClass() const { return _RUNTIME_CLASS(CMyDlg); }
John