使用MFC宏与模板

4

能否从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这里
2个回答

6

您需要使用BEGIN_TEMPLATE_MESSAGE_MAP而不是BEGIN_MESSAGE_MAP。


1
+1 感谢,但是它不能处理多个模板参数,就像上面的示例代码一样。 - SmacL
2
抱歉,我没有检查你的代码。我只是阅读了消息映射和模板,并考虑了BEGIN_TEMPLATE_MESSAGE_MAP。无论如何,很高兴知道你解决了问题! - Javier De Pedro

5
更一般的宏和模板问题是因为“宏是愚蠢的”(商标)。
预处理器不关心< >或[]作为分组运算符,因此在解析宏调用时:
BEGIN_MESSAGE_MAP(CGlobalEditT<TYPE,ARG_TYPE>, CDialog)

它的翻译是:

它的翻译如下:

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

然后查找BEGIN_MESSAGE_MAP的定义,发现它是一个只有两个参数的宏,并大声抱怨。

这种情况有两种类型:

  • 在类或函数内部
  • 实际上声明模板类或模板函数

在后一种情况下,除非提供特定的宏,否则你几乎没有办法。

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

  • 使用 typedefCGlobalEditT<TYPE,ARG_TYPE> 提供一个不包含逗号的同义词
  • CGlobalEditT<TYPE,ARG_TYPE> 周围使用大括号来“隔离”逗号

当大括号起作用时,它很棒,但并非总是如此。

当它们不适用时,typedef 通常是一个合适的替代方案。无论如何,这是关于宏要记住的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接