如何定义函数指针,该函数指针与将lambda与Capture用作回调兼容

理查德·钱伯斯

我需要一个带有MFC项目的简单模态对话框的多种变体,我编写了一个简单的类,该类CDialogDlg扩展了标准MFCCDialog类,并包含用于实现特定于回调的钩子,这些回调通常作为该类中的方法实现CDialog这些回调(如果提供)在处理某些事件(如对话框初始化,确定按钮处理以及DoDataExchange()提供用于连接对话框类变量和实际对话框控件的方法)函数时使用。

该类的第一个版本使用标准函数进行回调。因此,扩展类的回调设置方法使用标准函数的地址设置函数指针。

void SetDataExchangeCallBack(void(*f)(CDataExchange* pDX)) { funcDX = f; };
void SetInitCallBack(void(*f)(CWnd *dlgWnd)) { funcInit = f; }
void SetOnOkCallBack(void(*f)(CWnd *dlgWnd, CDocument *pDoc)) { funcOK = f; }

然后我意识到我应该能够使用lambda而不是标准函数。Lambda的第一个版本使用与标准函数相同的参数,但没有捕获任何经过良好编译的变量,并且无法与扩展类中的现有方法和函数指针一起正常工作。

但是,当我尝试在回调setter方法中指定的lambda中捕获变量时,出现编译错误。

回顾传递捕获的lambda作为函数指针,将C ++的lambda和捕获作为函数指针传递给我,我得到的尝试是使用捕获执行lambda不会与我正在使用的函数指针和回调设置函数的定义一起编译。

因此,我决定我应该在类内添加一个额外的lambda特定功能指针,以及对现有方法的覆盖,并使用在类内使用lambda特定功能指针设置回调的其他方法。

问题:设置回调以接受带有捕获变量的lambda的回调函数中的函数指针定义和参数定义应该是什么样?我想CPCSampleDoc *pDoc在方法中捕获局部变量CPCSampleView::OnDisplayReportList ()此变量包含指向CDocument我要捕获的视图派生对象的指针,而不是使用存储它的方法,然后执行操作static_cast以将其恢复为当前版本的未捕获的lambda。

源代码

CDialogDlg扩展CDialog如下所示:

class CDialogDlg : public CDialog
{
    // Construction
    void(*funcDX)(CDataExchange* pDX);
    void(*funcDXpDoc)(CDataExchange* pDX, CDocument *pDoc);
    void(*funcInit)(CWnd *dlgWnd);
    void(*funcOK)(CWnd *dlgWnd, CDocument *pDoc);
    CDocument *m_pDoc;

public:
    CDialogDlg(UINT nIDTemplate, CWnd* pParentWnd = NULL, void(*f)(CDataExchange* pDX) = NULL) : CDialog(nIDTemplate, pParentWnd) { funcDX = f; funcInit = NULL; }
    CDialogDlg(UINT nIDTemplate, CDocument *pDoc, CWnd* pParentWnd = NULL, void(*f)(CDataExchange* pDX, CDocument *pDoc) = NULL) : CDialog(nIDTemplate, pParentWnd) {
        funcDX = NULL; funcDXpDoc = f; funcInit = NULL; m_pDoc = pDoc;
    }

    void SetDataExchangeCallBack(void(*f)(CDataExchange* pDX)) { funcDX = f; };
    void SetInitCallBack(void(*f)(CWnd *dlgWnd)) { funcInit = f; }
    void SetOnOkCallBack(void(*f)(CWnd *dlgWnd, CDocument *pDoc)) { funcOK = f; }

    // Dialog Data
    //{{AFX_DATA(CCashierNoDlg)
    //}}AFX_DATA

    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CCashierNoDlg)
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

protected:
    // Generated message map functions
    //{{AFX_MSG(CCashierNoDlg)
    virtual BOOL OnInitDialog();
    virtual void OnOK();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CDialogDlg, CDialog)
    //{{AFX_MSG_MAP(CCashierNoDlg)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CDialogDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    if (funcDX) funcDX(pDX);
    if (funcDXpDoc) funcDXpDoc(pDX, m_pDoc);
    //{{AFX_DATA_MAP(CCashierNoDlg)
    //}}AFX_DATA_MAP
}

BOOL CDialogDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    if (funcInit) funcInit(this);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}

void CDialogDlg::OnOK()
{
    if (funcOK) funcOK(this, m_pDoc);
    CDialog::OnOK();
}

CView由菜单选择触发方法将显示一个对话框,其中列出了可供选择的项目。所显示的对话框是CDialogDlg具有特定对话框模板ID对象。对于特殊处理,我使用了两个不同的回调,这些回调当前正在使用无法捕获的lambda。结果如下:

void CPCSampleView::OnDisplayReportList ()
{
    CPCSampleDoc *pDoc = GetDocument();

    CDialogDlg myDialog(IDD_DIALOG_REPORTLIST, pDoc, this, [](CDataExchange* pDX, CDocument *pDoc) {
        if (pDX->m_bSaveAndValidate) {
        }
        else {
            CPCSampleDoc *pDocDoc = static_cast<CPCSampleDoc *>(pDoc);
            POSITION pos = NULL;

            do {
                CPCSampleDoc::ListReportList sectionHeader;
                CListBox *x = static_cast<CListBox *>(pDX->m_pDlgWnd->GetDlgItem(IDC_LIST1));

                pos = pDocDoc->GetReportSectionHeader(pos, sectionHeader);
                x->AddString(sectionHeader.m_SectionTitle);
            } while (pos);
        }
    });

    myDialog.SetOnOkCallBack([](CWnd *dlgWnd, CDocument *pDoc) {
        CPCSampleDoc *pDocDoc = static_cast<CPCSampleDoc *>(pDoc);
        CListBox *x = static_cast<CListBox *>(dlgWnd->GetDlgItem(IDC_LIST1));
        int iPtr = x->GetCurSel();
        POSITION pos = NULL;

        do {
            CPCSampleDoc::ListReportList sectionHeader;

            pos = pDocDoc->GetReportSectionHeader(pos, sectionHeader);
            if (iPtr < 1) {
                pDocDoc->MoveToReportSectionHeader(sectionHeader.m_ListOffset);
                break;
            }
            iPtr--;
        } while (pos);
    });

    myDialog.DoModal();
}
贾罗德42

您可能会std::function允许捕获lambda和其他函子以及常规函数指针:

void(*funcDX)(CDataExchange* pDX);
void(*funcDXpDoc)(CDataExchange* pDX, CDocument *pDoc);
void(*funcInit)(CWnd *dlgWnd);
void(*funcOK)(CWnd *dlgWnd, CDocument *pDoc);

变成

std::function<void(CDataExchange*)> funcDX;
std::function<void(CDataExchange*, CDocument*)> funcDXpDoc;
std::function<void(CWnd*)> funcInit;
std::function<void(CWnd*, CDocument*)> funcOK;

您的设置者/构造者也应该将指针功能更改为std::function

void SetInitCallBack(std::function<void(CWnd*)> f) { funcInit = f; }

其他用法相同:

if (funcDX) funcDX(pDX);

要么

funcInit = nullptr;

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将C函数指针传递给emscripten回调

回调:将函数指针作为参数并传递附加的参数

该函数如何执行回调?

如何使用从C ++到C#dll的非托管导出发送函数指针以用作回调

如何将指针/数组作为参数传递给 GTK 回调函数?

使用函数指针作为回调

在定义该函数的函数外部操作局部静态指针变量

有关函数指针和回调函数定义的示例

如何创建通用函数,该函数将返回c ++中任何级别的指针的值?

如何访问C ++函数,该函数将指针作为来自C#的输入参数

定义一个返回函数指针的函数,该函数指针也返回不带typedef的函数指针

将指针传递给函数回调

C回调函数的C ++“动态”函数指针

回调函数和函数指针绑定的向量

BST的C ++中的回调函数和函数指针故障

函数的名称。它是该函数的指针吗?

如何转发声明一个函数,该函数将指向函数的指针作为参数?

将转发lambda转换为函数指针

将捕获lambda作为函数指针传递

是否允许将指向模板函数的指针传递给C库?(作为回调)

C++:将 lambda 指针作为函数指针传递

C中没有函数指针的回调

函数指针作为 st 中的事件回调

C ++无法从回调函数中的“ this”访问对象指针

使用ReactJs从地图回调函数内部使用“ this”指针

在 Swift 中使用函数指针回调方法

MCU上的RTC-函数指针和回调

使用函数指针作为 UI-Button 回调的缺点

如何将成员函数作为回调参数传递给需要`typedef-ed`自由函数指针的函数?