4

Is it possible to derive and use a C++ template class from a MFC class such as CDialog. I've tried, but the implementation falls over with the MFC macros used for message routing. For example;

template<class TYPE, class ARG_TYPE>
class CMyDialogT : public CDialog
{
public:
    CMyDialogT(CMyContainerT<TYPE,ARG_TYPE> *pData,CWnd* pParent = NULL);  
    CMyContainerT<TYPE,ARG_TYPE> *m_pData;
    // Generated message map functions
    //{{AFX_MSG(CMyDialogT)
    afx_msg void OnUpdateMyControl();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

template<class TYPE, class ARG_TYPE>
CMyDialogT<TYPE,ARG_TYPE>::CMyDialogT(CMyContainerT<TYPE,ARG_TYPE> *pData,CWnd* pParent)
    : CDialog(CMyDialogT::IDD, pParent)
{
    m_pData = pData;
}

BEGIN_MESSAGE_MAP(CGlobalEditT<TYPE,ARG_TYPE>, CDialog)
    //{{AFX_MSG_MAP(CGlobalEditT)
    ON_EN_UPDATE(IDC_MY_CONTROL, OnUpdateMyControl)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

The above fails to compile with a sequence of messages starting as follows;

 warning C4002: too many actual parameters for macro 'BEGIN_MESSAGE_MAP'
 error C2653: 'TYPE' : is not a class or namespace name

Is there any workaround for this, other than manually unrolling the MFC macros? I can't use template specialisation at this point, as given in a similar question here as I don't know all the possible values of TYPE and ARG_TYPE.

Another way of looking at the question would be 'can I embed a template class in another class without either specialising the template or making the host class a template class'. I can't answer this one either, I suspect the answer may be No.

Edit Partial solution for single type templates on MSDN here

Community
  • 1
  • 1
SmacL
  • 22,555
  • 12
  • 95
  • 149

2 Answers2

6

You have to use BEGIN_TEMPLATE_MESSAGE_MAP instead of BEGIN_MESSAGE_MAP.

Javier De Pedro
  • 2,219
  • 4
  • 32
  • 49
  • 1
    +1 thanks, but it doesn't work with more than one template argument, as in the sample code above. – SmacL Jan 04 '12 at 15:13
  • 2
    I didn't check your code, sorry...I just read message map and templates and thought about BEGIN_TEMPLATE_MESSAGE_MAP. Anyway, good to know you solved your problem! – Javier De Pedro Jan 04 '12 at 17:12
5

The more general problem of macros and templates is because Macros are Stupid (tm).

The preprocessor does not care for <> or [] as grouping operators, therefore when parsing the macro invocation:

BEGIN_MESSAGE_MAP(CGlobalEditT<TYPE,ARG_TYPE>, CDialog)

It translates to:

  • Macro name: BEGIN_MESSAGE_MAP
  • Argument 1: CGlobalEditT<TYPE
  • Argument 2: ARG_TYPE>
  • Argument 3: CDialog

Then looks up the definition of BEGIN_MESSAGE_MAP, realizes it is a macro with only 2 arguments, and complains lowdly.

There are two types of situations in which this can happen:

  • within a class or a function
  • to actually declare a template class or a template function

In the latter case, you are more or less screwed, unless specific macros are provided.

In the former case, you have two solutions:

  • Using a typedef to provide a synonym to CGlobalEditT<TYPE,ARG_TYPE> that does not contain a comma
  • Using braces around CGlobalEditT<TYPE,ARG_TYPE> to "isolate" the comma

When braces work, it's great, however it's not always the case.

When they don't, typedef is often a suitable alternative.

In any case, it is something to keep in mind about macros.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722