我有一个使用OCCI Oracle API访问数据库的OracleConnection类。现在我需要从数据库中获取多行记录,这是通过ResultSet::getDataBuffer(...)API的函数。此函数接受一系列参数,其中一个是定义可以包含的数据类型的大枚举。
显然,我不希望在应用程序代码中使用Oracle API类型,因此其他API可以与此API互换。所以我的问题是,在我的函数包装器中,如何最好地接受这个类型参数?我应该只创建一个枚举并只接受我需要的类型,或者模板可以帮助我在这里映射到我拥有的OracleConnection类中OCCI的枚举吗?
void setDataBuffer(
unsigned int colIndex,
void *buffer,
Type type,
sb4 size = 0,
ub2 *length = NULL,
sb2 *ind = NULL,
ub2 *rc = NULL);这里的Type是一个枚举,看起来像这样:
enum Type
{
OCCI_SQLT_CHR=SQLT_CHR,
OCCI_SQLT_NUM=SQLT_NUM,
OCCIINT = SQLT_INT,
OCCIFLOAT = SQLT_FLT,
OCCIBFLOAT = SQLT_BFLOAT,
OCCIBDOUBLE = SQLT_BDOUBLE,
OCCIIBFLOAT = SQLT_IBFLOAT,
OCCIIBDOUBLE = SQLT_IBDOUBLE,
OCCI_SQLT_STR=SQLT_STR,
OCCI_SQLT_VNU=SQLT_VNU,
OCCI_SQLT_PDN=SQLT_PDN,
OCCI_SQLT_LNG=SQLT_LNG,
OCCI_SQLT_VCS=SQLT_VCS,
.... (about 2x as many to go)我的包装器如下所示:
void setDataBuffer(unsigned int colIndex, void * buffer, unsigned long size = 0, int type /*use int or template or redefine own Type Enum?*/, unsigned short * length = NULL, signed short * ind = NULL, unsigned short * rc = NULL)发布于 2011-04-05 20:54:38
一种选择是使您的函数成为模板,然后使用特征类将模板类型转换为表示各种Oracle类型的值。
特征类可能如下所示:
template <typename T>
struct oracle_type_traits;
template <> // create a specialization for each relevant type
struct oracle_type_traits<double> {
static const value = OCCIBDOUBLE // its value member should be the value you want to map to
};现在,下面的代码将为您提供double的Oracle类型id
oracle_type_traits<double>::value在setDataBuffer<T>(...)内部,只需检查oracle_type_traits<T>::value即可获得相应的Oracle类型ID。
发布于 2011-04-05 20:56:04
从包装器用户的POV来看,最好是调用重载函数或函数(成员)模板,然后将适当类型的对象传递给这些模板,然后这些模板会神奇地为该类型做正确的事情。也就是说,对于您的类(或Oracle API)支持的任何类型的T,最好有一个函数getData(unsigned int colIndex, T&),它将找出必要的缓冲区大小,分配缓冲区,确定正确的枚举,并调用Oracle API函数。
我相信您可以弄清楚大部分细节,可能除了如何将类型映射到enum之外,所以这就是我要列出的内容。
基本上,我认为有两种可能,一种(使用编译时列表)更适合需要支持的类型,另一种(使用特征)需要使用,因为除了将类型映射到enum之外,还需要使用更多特定于类型的方法。
特征方法使用起来非常简单,但是如果你有很多类型的话就很乏味了:
template<typename T>
struct get_data_buffer_traits;
template<>
struct get_data_buffer_traits<int> {
Type type OCCIINT;
};
template<>
struct get_data_buffer_traits<float> {
Type type OCCIBFLOAT;
};然后,您可以使用get_data_buffer_traits<T>::type将作为T传递给模板的类型映射到正确的enum值。
此特征模板也是您可以放置通用数据检索函数可能需要的任何其他特定类型操作的地方(例如在缓冲区中的内容和实际类型之间进行转换,如果这不是直接转换的话)。如果您没有其他东西可以放入这些特征中,您可以使用宏来使定义这些特征变得更容易:
#define DEFINE_GET_DATA_BUFFER_TRAITS(Type_,Enum_) \
template<> struct get_data_buffer_traits<Type_> { Type type Enum_; };
DEFINE_GET_DATA_BUFFER_TRAITS(int , OCCIINT );
DEFINE_GET_DATA_BUFFER_TRAITS(float, OCCIBFLOAT);
...
#undef DEFINE_GET_DATA_BUFFER_TRAITS但是,如果是这样的话,您还可以创建一个编译时映射来映射这两者,并(在编译时)搜索正确的enum值。如果您手头没有提供此功能的模板元库,请看下面的大纲,了解如何自己完成此操作:
// Beware, brain-compiled code ahead!
struct nil {};
template< typename HType
, Type HEnum
, class T >
struct set_data_buffer_type_map_node {
typedef HType head_type
enum { head_enum = HEnum };
typedef T tail_type;
};
typedef
set_data_buffer_type_map_node< int , OCCIINT
set_data_buffer_type_map_node< float, OCCIBFLOAT
...
nil
> > // either count or keep adding these until compiler accepts :)
set_data_buffer_type_map;
template< typename T, class Map >
struct getter {
// recurse towards tail
Type get_enum() { return getter<T,typename Map::tail_type>::get_enum(); }
};
template< typename T, Type HEnum, class Tail >
struct getter< T, set_data_buffer_type_map<T,HEnum,Tail> > {
// current node has T as HType
Type get_enum() { return set_data_buffer_type_map<T,HEnum,Tail>::head_enum; }
};
template< typename T, typename HType, Type HEnum, >
struct getter< T, set_data_buffer_type_map<T,HEnum,nil> > {
// no function here, so compile-time error
};
template< typename T>
Type get_type_enum()
{
return getter<T, set_data_buffer_type_map>::get_enum();
}(注意:这只是一个提纲。我甚至没有尝试过编译它。)
发布于 2011-04-05 20:24:03
我将建议使用枚举选项。使用它作为模板意味着你的API用户应该对之前的所有类型都有所了解,这可能有点困难。将其用作枚举还为它们提供了引用枚举的选项,并决定哪种SQL类型适合需求。
https://stackoverflow.com/questions/5551330
复制相似问题