C++ 处理重复序言/正文/结束语模式的建议方法

C++ 处理重复序言/正文/结束语模式的建议方法,c++,C++,我有一个场景,在这个场景中,我有很多具有以下模式的函数 RETURN_TYPE FOO( TYPE PARM1, TYPE PARM2) { PROLOG(PARM1, PARM2); //FOO_BODY EPILOG(PARM1, PARM2); } 考虑一个遵循上述模式的示例函数 SQLRETURN SQLGetInfo( SQLHDBC ConnectionHandle, SQLUSMALLINT

我有一个场景,在这个场景中,我有很多具有以下模式的函数

RETURN_TYPE FOO(
    TYPE PARM1,
    TYPE PARM2)
    {
    PROLOG(PARM1, PARM2);
    //FOO_BODY
    EPILOG(PARM1, PARM2);
    }
考虑一个遵循上述模式的示例函数

SQLRETURN SQLGetInfo(
    SQLHDBC         ConnectionHandle,
    SQLUSMALLINT    InfoType,
    SQLPOINTER      InfoValuePtr,
    SQLSMALLINT     BufferLength,
    SQLSMALLINT *   StringLengthPtr)
    {
    // ******** Prolog(InfoValuePtr, BufferLength) *************
    CComSafeArray<BYTE> _InfoValuePtr(BufferLength);
    LPBYTE pData;
    // **********************************************************
    SQLRETURN  rc =  p->SQLGetInfo(
        reinterpret_cast<PSSQLHSTMT>(ConnectionHandle),
        InfoType,
        _InfoValuePtr,
        BufferLength,
        StringLengthPtr);
    // ******** Epilog(InfoValuePtr) ******************************
    ::SafeArrayAccessData(_InfoValuePtr, reinterpret_cast<void **>(&pData));
    memcpy_s(InfoValuePtr, BufferLength, pData, _InfoValuePtr.GetCount());
    ::SafeArrayUnaccessData(_InfoValuePtr);
    return rc;
    // *************************************************************
    }
SQLRETURN SQLGetInfo(
SQLHDBC连接句柄,
SQLUSMALLINT信息类型,
SQLPOINTER InfoValuePtr,
SQLSMALLINT缓冲区长度,
SQLSMALLINT*StringLengthPtr)
{
//*******序言(InfoValuePtr,BufferLength)*************
CComSafeArray_InfoValuePtr(缓冲区长度);
LPBYTE-pData;
// **********************************************************
SQLRETURN rc=p->SQLGetInfo(
重新解释铸件(连接手柄),
信息类型,
_InfoValuePtr,
缓冲长度,
StringLengthPtr);
//*********结束语(InfoValuePtr)******************************
::安全阵列访问数据(_InfoValuePtr,reinterpret_cast(&pData));
memcpy_s(InfoValuePtr,BufferLength,pData,_InfoValuePtr.GetCount());
::safearrayunacessdata(_InfoValuePtr);
返回rc;
// *************************************************************
}
我的困境是,我有点不习惯一次又一次地重复相同的代码模式,这在开发过程中容易出错,并且代码膨胀。即使在明天,改变某些东西也意味着精心地改变每一件事,使之与变化保持一致

处理模式的建议方法/最佳实践是什么<代码>宏,
模板


注意我们仍然没有使用boost,添加boost仅仅是为了解决这个问题在这里可能不是一个选项

@Abhijit:我自己的直觉也倾向于模板。但是,你上面的例子看起来不像你上面给出的简化模型。如果确实有大量的函数除了中间的部分外看起来都一样,那么模板可以清理这些函数。将模板参数设置为函数指针,指向与序言和结束语挂钩的函数。这几乎是咖喱的一种变体,但不完全是

在不完全理解上述示例的情况下,以下是如何将其转换为使用模板的示意图。由于示例的主体只是一个函数调用,因此此转换并没有真正公开模式的功能。但是,它应该有希望给出一个想法

// Define the "body function" in a typedef, for sanity's sake
typedef SQLRETURN 
            (*SQLGetInfoFunc)(
                PSSQLHSTMT, 
                SQLUSMALLINT,
                CComSafeArray<BYTE>,
                SQLSMALLINT, 
                SQLSMALLINT*
            );  

// Templated version of SQLGetInfo
template <SQLGetInfoFunc *F>
SQLRETURN SQLGetInfo(
    SQLHDBC         ConnectionHandle,
    SQLUSMALLINT    InfoType,
    SQLPOINTER      InfoValuePtr,
    SQLSMALLINT     BufferLength,
    SQLSMALLINT *   StringLengthPtr)
    {
    // ******** Prolog(InfoValuePtr, BufferLength) *************
    CComSafeArray<BYTE> _InfoValuePtr(BufferLength);
    LPBYTE pData;
    // **********************************************************
    SQLRETURN  rc =  F(
        reinterpret_cast<PSSQLHSTMT>(ConnectionHandle),
        InfoType,
        _InfoValuePtr,
        BufferLength,
        StringLengthPtr);
    // ******** Epilog(InfoValuePtr) ******************************
    ::SafeArrayAccessData(_InfoValuePtr, reinterpret_cast<void **>(&pData));
    memcpy_s(InfoValuePtr, BufferLength, pData, _InfoValuePtr.GetCount());
    ::SafeArrayUnaccessData(_InfoValuePtr);
    return rc;
    // *************************************************************
    }
它的输出如下:

Before: af =  1 2 3 4 5 6 7 8 9 10
After apply_to_array<fred>(af):  af =  101 102 103 104 105 106 107 108 109 110
Before: ab =  1 2 3 4 5 6 7 8 9 10
After apply_to_array<barney>(ab):  ab =  201 202 203 204 205 206 207 208 209 210
Before:af=12345678910
将_应用于_阵列(af)后:af=101 102 103 104 105 106 107 108 109 110
之前:ab=12345678910
将_应用于_数组(ab)后:ab=201 202 203 204 205 206 207 208 209 210

@Abhijit:我自己的直觉也倾向于模板。但是,你上面的例子看起来不像你上面给出的简化模型。如果确实有大量的函数除了中间的部分外看起来都一样,那么模板可以清理这些函数。将模板参数设置为函数指针,指向与序言和结束语挂钩的函数。这几乎是咖喱的一种变体,但不完全是

在不完全理解上述示例的情况下,以下是如何将其转换为使用模板的示意图。由于示例的主体只是一个函数调用,因此此转换并没有真正公开模式的功能。但是,它应该有希望给出一个想法

// Define the "body function" in a typedef, for sanity's sake
typedef SQLRETURN 
            (*SQLGetInfoFunc)(
                PSSQLHSTMT, 
                SQLUSMALLINT,
                CComSafeArray<BYTE>,
                SQLSMALLINT, 
                SQLSMALLINT*
            );  

// Templated version of SQLGetInfo
template <SQLGetInfoFunc *F>
SQLRETURN SQLGetInfo(
    SQLHDBC         ConnectionHandle,
    SQLUSMALLINT    InfoType,
    SQLPOINTER      InfoValuePtr,
    SQLSMALLINT     BufferLength,
    SQLSMALLINT *   StringLengthPtr)
    {
    // ******** Prolog(InfoValuePtr, BufferLength) *************
    CComSafeArray<BYTE> _InfoValuePtr(BufferLength);
    LPBYTE pData;
    // **********************************************************
    SQLRETURN  rc =  F(
        reinterpret_cast<PSSQLHSTMT>(ConnectionHandle),
        InfoType,
        _InfoValuePtr,
        BufferLength,
        StringLengthPtr);
    // ******** Epilog(InfoValuePtr) ******************************
    ::SafeArrayAccessData(_InfoValuePtr, reinterpret_cast<void **>(&pData));
    memcpy_s(InfoValuePtr, BufferLength, pData, _InfoValuePtr.GetCount());
    ::SafeArrayUnaccessData(_InfoValuePtr);
    return rc;
    // *************************************************************
    }
它的输出如下:

Before: af =  1 2 3 4 5 6 7 8 9 10
After apply_to_array<fred>(af):  af =  101 102 103 104 105 106 107 108 109 110
Before: ab =  1 2 3 4 5 6 7 8 9 10
After apply_to_array<barney>(ab):  ab =  201 202 203 204 205 206 207 208 209 210
Before:af=12345678910
将_应用于_阵列(af)后:af=101 102 103 104 105 106 107 108 109 110
之前:ab=12345678910
将_应用于_数组(ab)后:ab=201 202 203 204 205 206 207 208 209 210

template始终是最干净的解决方案,但当它没有多大帮助时,它就是你最好的朋友。我总是赞成宏,否则代码重复是必要的,因为我认为简单的维护是最重要的,而可辨认性只是其中的一部分。现在我几乎不能编写一行C++而不需要Boost。@ BrunoCoDurt:在开发大型组织时,开发者可能没有什么发言权。因此,让我们从现在开始不要讨论这个话题:-)。另外,我想看看我们如何使用templatestemplate解决这个问题。Template始终是最干净的解决方案,但当它没有多大帮助时,它就是您最好的朋友。我总是赞成宏,否则代码重复是必要的,因为我认为简单的维护是最重要的,而可辨认性只是其中的一部分。现在我几乎不能编写一行C++而不需要Boost。@ BrunoCoDurt:在开发大型组织时,开发者可能没有什么发言权。因此,让我们从现在开始不要讨论这个话题:-)。另外,我想看看我们如何使用Templates解决这个问题谢谢你的回答。我需要一些时间来理解这个模式,以满足我的需要,因为几乎不需要定制,但无论如何我喜欢你的想法。请注意,我计划在接下来的几天里为这件事开一个悬赏,并等待更多的答案。如果你的是一个有效的,我会奖励你的赏金。在那之前,我会保留我的选择:如果你需要澄清,有两件事。1.
p
是指向COM接口2的指针。这仍然需要复制代码(但我看到了一些机会),因为变量名称因函数而异,但类型和操作保持不变。3.它赢了;不管被调用的函数是否是方法,因为指向成员函数的指针可以很容易地包装起来。谢谢您的回答。我需要一些时间来理解这个模式,以满足我的需要,因为几乎不需要定制,但无论如何我喜欢你的想法。请注意,我计划在接下来的几天里为这件事开一个悬赏,并等待更多的答案。如果你的是一个有效的,我会奖励你的赏金。在那之前,我会保留我的选择:如果