gpt4 book ai didi

C++ 减少冗余

转载 作者:行者123 更新时间:2023-11-30 04:49:25 25 4
gpt4 key购买 nike

我在一个 DLL 中有很多 C++ 函数,我专门为 Excel 调用。

我经常将包含 SafeArray 的 OLE VARIANT 作为参数传递给这些函数。

我编写了一个函数来充当守卫,以确保传递的 VARIANT 实际上包含一个 SafeArray,并且该数组在数据类型和维数方面都是适合该场合的类型。

如果满足这三个条件,该函数将返回指向第一个元素的指针,并且还有两个输出参数返回每个维度中的元素数量(注意:我只关心一维和二维 SafeArrays)。

函数如下:

PVOID SafeArrayDataPointer(VARIANT &v, const long &ArrayType, const long &ArrayDims, long &Elems1D, long &Elems2D) {

SAFEARRAY* pSafeArray = NULL;

if ( V_VT(&v) & VT_ARRAY ) {

if ( ArrayType != (V_VT(&v) & VT_TYPEMASK) ) return NULL;

pSafeArray = V_ARRAY(&v);
if ( ArrayDims != pSafeArray->cDims ) return NULL;

switch (ArrayDims) {
case 2:
Elems1D = (pSafeArray->rgsabound)[1].cElements;
Elems2D = (pSafeArray->rgsabound)[0].cElements;
break;
case 1:
Elems1D = (pSafeArray->rgsabound)[0].cElements;
Elems2D = 0;
break;
default:
Elems1D = 0;
Elems2D = 0;
break;
}

return pSafeArray->pvData;

} else return NULL;

}

这个函数运行良好,允许我通过这样调用方便地获取数据指针并获取每个维度中的元素数(假设 vData 是从 Excel 传递的 VARIANT:

pDataArray = (VARIANT*) SafeArrayDataPointer(vData, VT_VARIANT, 2, Elems1D, Elems2D); if (pDataArray == NULL) goto error1;

但是,有两点我不喜欢这个:

1.) 由于该函数返回一个 PVOID,我必须转换为相关的指针类型...但这是多余的,因为我已经在第二个参数中指定了哪种类型的数组必须包含在 VARIANT 中。例如,在不同的情况下,我可能需要确保数组具有长值:

pDataArray = (long*) SafeArrayDataPointer(vData, VT_I4, 1, Elems1D, Junk); if (pDataArray == NULL) goto error1;

同样,这工作正常,但它是多余的。我更喜欢某种允许函数返回正确类型指针的机制。我希望这可以在没有模板的情况下完成。

2.) 我不知道如何在第二个示例中不使用 Junk 参数,其中我指定数组必须是 1d。显然,在这种情况下,二维中没有元素。

最佳答案

如果您不想使用模板,也不需要专门的函数,您可以使用gross macro 来解决第一个关于必须从PVOID 转换的问题。每次打电话SafeArrayVariantPointer :

像这样:

#define CAST_TYPE_VT_VARIANT (VARIANT *)
#define CAST_TYPE_VT_LONG (long *)

#define SAFE_ARRAY_DATA_POINTER(vData, vType, dimSize, elems1D, elems2D) \
CAST_TYPE_##vType SafeArrayDataPointer((vData), (vType), (dimSize), (elems1D), (elems2D))

然后你可以这样调用:

VARIANT *pDataArray = SAFE_ARRAY_DATA_POINTER(vData, VT_VARIANT, 2, Elems1D, Elems2D);

但是首先你需要改变你的方法签名所以ArrayType参数被视为 long不是const long & .

请注意,这假设第二个参数为 SAFE_ARRAY_DATA_POINTER宏必须是对应于您定义的 CAST_TYPE_* 宏之一的文字。它不能是一个变量。

关于冗余的第二个问题Junk参数,你可以创建一个重载的 SafeArrayDataPointer函数只返回第一个维度的大小。它可以调用第一个版本SafeArrayDataPointer并丢弃第二个维度的大小。

类似于:

PVOID SafeArrayDataPointer(VARIANT &v, long ArrayType, const long &ArrayDims, long &Elems1D) 
{
long Elems2D;
PVOID *toReturn = SafeArrayDataPointer(v, ArrayType, ArrayDims, Elems1D, Elems2D);
if (Elems2D != 0) toReturn = NULL;
return toReturn;
}

但是,要解决这个问题,我可能会使用模板。

首先,创建一组 array_type_traits暴露 typedef 的类对于你的 Actor 类型,给定一个 long 代表 VT_LONG , VT_VARIANT

//Generic array_type_traits class
template<long array_type>
class array_type_traits
{
public:
typedef PVOID cast_type;
};

//Specialized for VT_LONG
template<>
class array_type_traits<VT_LONG>
{
public:
typedef long * cast_type;
};

//Specialized for VT_VARIANT
template<>
class array_type_traits<VT_VARIANT>
{
public:
typedef VARIANT * cast_type;
};

继续为您拥有的每个 VT_* 类型专门化这些。

接下来,封装你的SafeArrayDataPointer类中的函数 SafeArrayDataPointerBase .

//Base class which has one static function Get() that returns a PVOID
class SafeArrayDataPointerBase
{
protected:
static PVOID Get(VARIANT& vData, long vType, long dimSize, long& elems1D, long& elems2D)
{
// Place your SafeArrayDataPointer function code here
}
};

现在创建您的类,它将调用`SafeArrayDataPointerBase::Get(),然后将结果转换为正确的类型。

template<long ArrayType>
class SafeArrayDataPointer : public SafeArrayDataPointerBase
{
public:
typedef typename array_type_traits<ArrayType>::cast_type cast_type;

static cast_type Get(VARIANT& v, long ArrayDims, long& Elems1D, long& Elems2D)
{
return (cast_type) SafeArrayDataPointerBase::Get(v, ArrayDims, ArrayType, Elems1D, Elems2D);
}
};

最后,您可以这样调用模板类:

VARIANT *vp = SafeArrayDataPointer<VT_VARIANT>::Get(v, ArrayDims, Elems1D, Elems2D); 
long *vl = SafeArrayDataPointer<VT_LONG>::Get(v, ArrayDims, Elems1D, Elems2D);

关于C++ 减少冗余,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55404089/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com