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

Suggested Approach in dealing with repetitive Prolog / Body / Epilog Pattern

本文关键字:模式 方法 Epilog 正文 Prolog 处理      更新时间:2023-10-16

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

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

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

@Abhijit:我自己的直觉也倾向于模板。 但是,你上面的例子看起来并不像你上面给出的简化模型。 如果您确实有大量看起来相同的函数,除了某些中间部分,那么模板可以清理它。 使模板参数成为指向挂钩到 prolog 和 epilog 的函数的函数指针。 这几乎是咖喱的变体,但不完全是。

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

// 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