将MFC宏与模板一起使用

Using MFC macros with templates

本文关键字:一起 MFC      更新时间:2023-10-16

是否可以从MFC类(如CDialog)派生并使用C++模板类。我试过了,但实现失败了,因为MFC宏用于消息路由。例如

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()

以上未能编译,消息序列如下所示;

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

除了手动展开MFC宏之外,还有其他解决方法吗?在这一点上,我不能使用模板专业化,正如这里的一个类似问题中所给出的,因为我不知道TYPE和ARG_TYPE的所有可能值。

另一种看待这个问题的方法是"我可以在不专门化模板或使宿主类成为模板类的情况下将模板类嵌入另一个类中吗?"。我也不能回答这个问题,我怀疑答案可能是否定的。

编辑MSDN上单一类型模板的部分解决方案,点击此处

您必须使用BEGIN_TEMPLATE_MESSAGE_MAP而不是BEGIN_MESSAGE_MAP。

宏和模板更常见的问题是因为宏是愚蠢的(tm)。

预处理器不关心<>[]作为分组运算符,因此在解析宏调用时:

BEGIN_MESSAGE_MAP(CGlobalEditT<TYPE,ARG_TYPE>, CDialog)

翻译过来就是:

  • 宏名称:BEGIN_MESSAGE_MAP
  • 参数1:CGlobalEditT<TYPE
  • 参数2:ARG_TYPE>
  • 自变量3:CDialog

然后查找BEGIN_MESSAGE_MAP的定义,意识到它是一个只有2个参数的宏,并低声抱怨。

有两种情况可能发生这种情况:

  • 在类或函数中
  • 实际声明模板类或模板函数

在后一种情况下,除非提供了特定的宏,否则您或多或少都会陷入困境。

在前一种情况下,您有两种解决方案:

  • 使用typedef为不包含逗号的CGlobalEditT<TYPE,ARG_TYPE>提供同义词
  • CGlobalEditT<TYPE,ARG_TYPE>周围使用大括号来"隔离"逗号

当支架工作时,它很好,但情况并非总是如此。

当他们不这样做时,typedef通常是一个合适的替代方案。

在任何情况下,都需要记住宏。