处理重复Prolog / Body / Epilog模式的建议方法

时间:2013-09-15 04:49:02

标签: c++

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

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;
    // *************************************************************
    }

我的困境是,我有点不舒服一次又一次地重复相同的代码模式,这在开发过程中容易出错并且代码膨胀很大。即使在明天,改变某些东西也意味着要细致地改变每一个事件,使其与变化保持一致。

处理模式的建议方法/最佳做法是什么? MacrosTemplates

注意我们仍然没有使用提升和添加提升只是为了解决这个问题可能不是这里的选择

1 个答案:

答案 0 :(得分:1)

@Abhijit:我自己的直觉也转向模板。但是,您上面的示例看起来并不像您在其上面提供的简化模型。如果你确实有大量的功能看起来相同,除了一些中间部分,那么模板可以清理它。使模板参数成为指向挂起prolog和epilog的函数的函数指针。这几乎是currying的变种,但不完全是。

如果不完全理解上面的示例,下面是如何将其转换为使用模板的草图。由于示例的主体只是一个函数调用,因此这种转换并不能真正暴露模式的强大功能。但是,它应该有一个想法。

// 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;
    // *************************************************************
    }

在此示例中,F是一个函数指针,您将其作为模板参数提供。也就是说,我注意到您的原始示例使用了p->SQLGetInfo,但我没有看到p的定义位置。

为了提供显示基本模式的完整示例,请考虑以下代码:

#include <iostream>

typedef int (*fxn)(int);

inline int fred(int x) 
{
    return x + 100;
}

inline int barney(int x)
{
    return x + 200;
}


template <fxn F>
void apply_to_array(int *array, int len)
{
    for (int i = 0; i < len; i++)
        array[i] = F(array[i]);
}

using namespace std;

void print_array(int *array, int len)
{
    for (int i = 0; i < len; i++)
        cout << " " << array[i];

    cout << endl;
}


int af[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int ab[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int main(void)
{
    cout << "Before: af = ";
    print_array(af, 10);

    apply_to_array<fred>(af, 10);

    cout << "After apply_to_array<fred>(af):  af = ";
    print_array(af, 10);

    cout << "Before: ab = ";
    print_array(ab, 10);

    apply_to_array<barney>(ab, 10);

    cout << "After apply_to_array<barney>(ab):  ab = ";
    print_array(ab, 10);

    return 0;
}

输出以下内容:

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