C++11 将方法作为参数传递

C++11 将方法作为参数传递,c++11,mfc,C++11,Mfc,我已经复习了这篇优秀的文章,但我仍然感到困惑。最终我将有10个行为相似的方法。下面是我已经写过的三个例子: void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID) { // We need to locate the name for this assignment auto iter = m_mapSwapAssignments.find(nID); if (iter

我已经复习了这篇优秀的文章,但我仍然感到困惑。最终我将有10个行为相似的方法。下面是我已经写过的三个例子:

void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
    // We need to locate the name for this assignment 
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->GetChairman());
        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = pReplacement->GetChairman();
            pReplacement->SetChairman(strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}

void CChristianLifeMinistryEditorDlg::OnSwapWithOpenPrayerAssignment(UINT nID)
{
    // We need to locate the name for this assignment 
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->GetOpenPrayer());
        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = pReplacement->GetOpenPrayer();
            pReplacement->SetOpenPrayer(strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}

void CChristianLifeMinistryEditorDlg::OnSwapWithClosePrayerAssignment(UINT nID)
{
    // We need to locate the name for this assignment 
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->GetClosePrayer());
        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = pReplacement->GetClosePrayer();
            pReplacement->SetClosePrayer(strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}
我想将每个事件处理程序中的代码编码到一个方法中

  • GetChairman
  • SetChairman
  • GetOpenPrayer
  • SetOpenPrayer
  • GetClosePrayer
  • SetClosePrayer
我试过这个:

void CChristianLifeMinistryEditorDlg::SwapAssignments(UINT nID, CString(*GetExistingName), void(*SetReplacementName)(CString))
{
    // We need to locate the name for this assignment 
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->(*GetExistingName));
        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = pReplacement->(*GetExistingName);
            pReplacement->(*SetReplacementName)(strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}
我发现生成错误:

如何将这些方法作为参数传递

我看到了另一个我希望可以使用的方法,但问题是被调用的方法是对象的成员。所以它不允许这样做


当前解决方法 目前,我已经实现了几个功能:

CString CChristianLifeMinistryEntry::GetName(SwapAssignment eAssignment)
{
    switch (eAssignment)
    {
    case SwapAssignment::Chairman:
        return GetChairman();
    case SwapAssignment::Counsellor1:
        return GetAuxiliaryCounsellor1();
    case SwapAssignment::Counsellor2:
        return GetAuxiliaryCounsellor2();
    case SwapAssignment::OpenPrayer:
        return GetOpenPrayer();
    case SwapAssignment::Treasures1:
        return GetTreasures1();
    case SwapAssignment::Treasures2:
        return GetTreasures2();
    case SwapAssignment::Living1:
        return GetLiving1();
    case SwapAssignment::Living2:
        return GetLiving2();
    case SwapAssignment::ConductorCBS:
        return GetCBSConductor();
    case SwapAssignment::ReaderCBS:
        return GetCBSReader();
    case SwapAssignment::ClosePrayer:
        return GetClosePrayer();
    }

    return _T("");
}

// AJT v18.1.6
void CChristianLifeMinistryEntry::SetName(CString strName, SwapAssignment eAssignment)
{
    switch (eAssignment)
    {
    case SwapAssignment::Chairman:
        SetChairman(strName);
        break;
    case SwapAssignment::Counsellor1:
        SetAuxiliaryCounsellor1(strName);
        break;
    case SwapAssignment::Counsellor2:
        SetAuxiliaryCounsellor2(strName);
        break;
    case SwapAssignment::OpenPrayer:
        SetOpenPrayer(strName);
        break;
    case SwapAssignment::Treasures1:
        SetTreasures1(strName);
        break;
    case SwapAssignment::Treasures2:
        SetTreasures2(strName);
        break;
    case SwapAssignment::Living1:
        SetLiving1(strName);
        break;
    case SwapAssignment::Living2:
        SetLiving2(strName);
        break;
    case SwapAssignment::ConductorCBS:
        SetCBSConductor(strName);
        break;
    case SwapAssignment::ReaderCBS:
        SetCBSReader(strName);
        break;
    case SwapAssignment::ClosePrayer:
        SetClosePrayer(strName);
        break;
    }
}
然后,我将我提到的代码稍加调整,移到一个新方法中:

// AJT v18.1.6
void CChristianLifeMinistryEditorDlg::SwapAssignments(UINT nID, SwapAssignment eAssignment)
{
    // We need to locate the name for this assignment 
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->GetName(eAssignment));
        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = pReplacement->GetName(eAssignment);
            pReplacement->SetName(strExistingName, eAssignment);
            if (pReplacement == m_pEntry) // Swapping assignments on same meeting!
                SetDlgItemText(IDC_COMBO_OCLM_CBS_READER, strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}
现在,我的11个处理程序与此类似:

// AJT v18.1.6
void CChristianLifeMinistryEditorDlg::OnSwapWithCBSReaderAssignment(UINT nID)
{
    SwapAssignments(nID, SwapAssignment::ReaderCBS);
}

它起作用了。但我看到我的问题中添加了一条新的注释,并带有一个链接,因此我将看看我是否能取得任何进展。

因此,让我们分阶段重构代码

第一阶段: 首先,在通用函数
OnSwapWith

template<typename Function>
void CChristianLifeMinistryEditorDlg::OnSwapWith(Function && function,
                                                 UINT        nID)
{
    // We need to locate the name for this assignment
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)pReplacement->GetChairman());

        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            function();
            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}

void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
    auto ChairmanAssignment = [&]() // capture by reference (i.e. &)
    {
        strReplacementName = pReplacement->GetChairman();
        pReplacement->SetChairman(strExistingName);
    };
    CChristianLifeMinistryEditorDlg::OnSwapWith(ChairmanAssignment, nID);
}

void CChristianLifeMinistryEditorDlg::OnSwapWithOpenPrayerAssignment(UINT nID)
{
    auto OpenPrayerAssignment = [&]() // capture by reference (i.e. &)
    {
        strReplacementName = pReplacement->GetOpenPrayer();
        pReplacement->SetOpenPrayer(strExistingName);
    };
    CChristianLifeMinistryEditorDlg::OnSwapWith(OpenPrayerAssignment, nID);
}

void CChristianLifeMinistryEditorDlg::OnSwapWithClosePrayerAssignment(UINT nID)
{
    auto ClosePrayerAssignment = [&]() // capture by reference (i.e. &)
    {
        strReplacementName = pReplacement->GetClosePrayer();
        pReplacement->SetClosePrayer(strExistingName);
    };
    CChristianLifeMinistryEditorDlg::OnSwapWith(ClosePrayerAssignment, nID);
}

// and similarly other functions can be defined
那么来电方呢

void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
    auto getter = [](CChristianLifeMinistryEntry * pReplacement) 
    { // remove the captures now, since we are getting the state with the pointer
        return pReplacement->GetChairman();
    };
    auto setter = [](CChristianLifeMinistryEntry * pReplacement,
                     CString               const & strExistingName) 
    {
        pReplacement->SetChairman(strExistingName);
    };
    CChristianLifeMinistryEditorDlg::OnSwapWith(getter, setter, nID);
}

最终工作代码 11个菜单事件处理程序类似于:

void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
    auto getter = [](CChristianLifeMinistryEntry * pReplacement)
    {
        return pReplacement->GetChairman();
    };
    auto setter = [](CChristianLifeMinistryEntry * pReplacement, 
                     CString                     & strExistingName)
    {
        pReplacement->SetChairman(strExistingName);
    };
    CChristianLifeMinistryEditorDlg::OnSwapWith(getter, setter,
                                                nID, IDC_COMBO_OCLM_CHAIRMAN);
}
模板化函数现在看起来像:

template<typename GetterFunction, typename SetterFunction>
void CChristianLifeMinistryEditorDlg::OnSwapWith(GetterFunction && getter,
                                                 SetterFunction && setter,
                                                 UINT              nID,
                                                 UINT              nReplacementCtrlID)
{
    // We need to locate the name for this assignment
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)getter(pReplacement));

        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = getter(pReplacement);
            setter(pReplacement, strExistingName);
            if (pReplacement == m_pEntry) // Swapping assignments on same meeting!
                SetDlgItemText(nReplacementCtrlID, strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}
模板
void CChristianLifeMinistryEditorDlg::OnSwapWith(GetterFunction&&getter,
setter函数和setter,
乌因特·奈德,
UINT重新替换Ctrlid)
{
//我们需要找到此任务的名称
自动iter=m_-mapSwapAssignments.find(nID);
if(iter!=m_mapSwapAssignments.end())
{
//我们找到了
CCHRISTIANLIFEMISTRYENTRY*PREPLACENT=m_地图通行证[nID];
CString strExistingName=\u T(“”),strReplacementName=\u T(“”);
GetDlgItemText(m_iSwapAssignmentSourceID,strExistingName);
CString struppt=\u T(“”);
strcompt.Format(\u T(“交换分配:\n\n%s-%s\n%s-%s\n\n请确认”),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
预放置->GetMeetingDateAsString(),
(LPCTSTR)吸气剂(预置换);
if(AfxMessageBox(strcompt,MB|i查询| MB|u YESNO)=idies)
{
strReplacementName=getter(预置换);
设置器(预定位,街道名称);
if(pReplacement==m_pEntry)//在同一个会议上交换任务!
SetDlgItemText(nReplacementCtrlID,StreexistingName);
SetDlgItemText(m_iSwapAssignmentSourceID,strReplacementName);
SetModified(真);
}
}
}

@IInspectable感谢您的链接。我正试图弄清楚那篇文章,但它让我的头受伤了……:)请尝试阅读以下内容:。如果你觉得它不那么伤脑筋,更接近你需要的东西,我可以帮助你进一步构建它。@badola感谢你提供了有用的答案链接。我这里的问题仍然是,这些示例都是当前类的成员函数。正如您在最后的代码中所看到的,我需要传递作为特定对象成员的函数,因为我们必须根据该对象中的成员变量获取/设置。仍然可以使用这种方法吗?通常在头文件中首选模板。虽然没有这样的限制,它必须在头文件中。我将尝试在半小时左右重构您的代码,并可能为您提供所需的答案。不要担心它会让人困惑,一开始它是对所有人的。@Andrew Truckle,如果这对你有效,那么我们可以进一步重构。请在您的代码库中使用它,并让我知道。我对你的变量知之甚少,所以没有做太多的修改。
template<typename GetterFunction, typename SetterFunction>
void CChristianLifeMinistryEditorDlg::OnSwapWith(GetterFunction && getter,
                                                 SetterFunction && setter,
                                                 UINT              nID,
                                                 UINT              nReplacementCtrlID)
{
    // We need to locate the name for this assignment
    auto iter = m_mapSwapAssignments.find(nID);

    if (iter != m_mapSwapAssignments.end())
    {
        // We found it
        CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
        CString strExistingName = _T(""), strReplacementName = _T("");
        GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);

        CString strPrompt = _T("");
        strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
            m_pEntry->GetMeetingDateAsString(),
            (LPCTSTR)strExistingName,
            pReplacement->GetMeetingDateAsString(),
            (LPCTSTR)getter(pReplacement));

        if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
        {
            strReplacementName = getter(pReplacement);
            setter(pReplacement, strExistingName);
            if (pReplacement == m_pEntry) // Swapping assignments on same meeting!
                SetDlgItemText(nReplacementCtrlID, strExistingName);

            SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
            SetModified(true);
        }
    }
}