如何为 CIOWrapper::Select 编写类型转换器

来源:互联网 发布:人物简笔画软件 编辑:程序博客网 时间:2024/06/04 18:14

如果你不知道这篇文章在说什么,请前往 http://blog.csdn.net/passfuhao/article/details/76545332,阅读本文的前半部分。

注:

        这算得上是DBIOWrapper的高级用法,需要较深的C++基础。绝大多数时候使用DBIOWrapper的默认实现既可,所以,你可能并非真的需要知悉以下内容。

        我仍然认为有必要解释一下如何为Select编写类型转换器(默认的转换器是VariantCast),因为转换器是DBIOWrapper的复杂和缺陷所在。另外我还认为一定会有人需要诸如“将数值转换为字符串”的诉求。


Select函数的声名如下:

templatetemplateVariantType > class CastType = VariantCasttypename ..._Types BOOL Select__out _Types&... Args );

        Select接受一个模板类(或模板结构)类型模板参数CastType作为转换器,和数个任意类型的输出参数,CastType的声名形式必须能够接受一个VariantType型的数值型模板参数作为源类型(参见表1.4中的“源类型”),其声名可能如下:

templatetypename VariantType > struct CustomizeVariantCast{ ... };

        CustomizeVariantCast结构的模板参数 VariantType 会被实例化为源类型,即:调用其成员函数Cast 时传递的第三个参数IDBVariant对象中存储的数据的类型。

CastType模板类(或结构)中还必须提供形如以下的名为Cast的静态成员函数:

static BOOL Cast( DestType &DestIFieldInfo *pFieldInfoIDBVariant *pSrc );

        其中 DestType 是用户调用Select函数时传递的参数类型,Cast函数负责将 pSrc中存储的数据转换为DestType类型并存储到Dest变量中,因为调用Select时可能会传递多个不同类型的参数,所以Cast函数也必须能接受多种不同类型的Dest参数,那么,其声名更可能是模板,如下:

templatetypename _Dty > static BOOL Cast_Dty &DestIFieldInfo *p1IDBVariant * pSrc );

        然而,这种模板化的版本中,它的模板参数_Dty可能是任意类型,我们不可能在这一个模板化的函数中根据_Dty 的不同而实现出转换,所以仍然无法为此版Cast编写实现。那么,我们需要对Cast函数特化,实现由IDBVariant向不同类型转换时的不同处理。

template<> static BOOLint &DestIFieldInfo *p1IDBVariant * pSrc );

template<> static BOOLdouble &DestIFieldInfo *p1IDBVariant * pSrc );

template<> static BOOL__int64 &DestIFieldInfo *p1IDBVariant * pSrc );

还可以通过重载来实现Cast函数,如下:

static BOOLint &DestIFieldInfo *p1IDBVariant *pSrc );

static BOOLdouble &DestIFieldInfo *p1IDBVariant *pSrc );

static BOOL__int64 &Dest, ...... );

等等等等的各种重载。

        当然,我们几乎可以肯定,并不是所有IDBVariant(pSrc )的类型(源类型)都可以向任何目的类型转换,例如:IDBVariant(pSrc)的类型为VariantTypeAString时,显然无法向char类型转换。所以,我们有了转换原则:只允许类型升宽,但不允许收窄(如,int可以向double转换,反之不行),这也是Select函数默认情况下使用的转换器(VariantCast)所施行的原则。

        另外,由于我们不应该把所有的源类型向目的类型的转换写在一个(转换器)类(或结构)中,所以,我们还需特化转换器,否则,我们大概会写出以下这样的代码:

templatetypename VariantTypestruct CustomizeVariantCast

{

       static BOOL Castdouble &DestIFieldInfo *pIDBVariant *pSrc )

       {

              ifpSrc->Type() == VariantTypeLong )

              {

                     // 实现转换

              }

              else ifpSrc->Type() == VariantTypeFloat )

              {

                     // 实现转换

              }

              else ifpSrc->Type() == VariantTypeAString )

              {

                     // 报告错误并返回FALSE

                     return FALSE;

              }

              ...

       }

};

        主要问题是 pSrc->Type() 会返回所有可能的源类型标识,那么各种源类型向double 类型的转换全部混在一起导致代码混乱而且需要花费运行时间,所以,特化转换器类(或结构)是个合理需求,做法如下:

template<> struct CustomizeVariantCas < VariantTypeLong > /* 仅当pSrc->Type() 返回 VariantTypeLong时调用此结构中的 Cast 成员函数。*/

{

       templatetypename _Dty > static BOOL Cast_Dty &DestIFieldInfo *pIDBVariant *pSrc )

       {

              printf"不支持向%s类型转换\n"typeid(_Dty).name() );

              return FALSE;    /* 不支持向 _Dty类型转换 */

       }

       // 实现向double类型转换

       static BOOL Castdouble &DestIFieldInfo *pIDBVariant *pSrc )

       {

              // pSrc->Type()返回VariantTypeNull的原因是 pSrc存储的对应数据库,表的单元的值为Null。

              Dest = pSrc->Type() == VariantTypeNull ? 0 : (double)pSrc->GetLong();

              return TRUE;

       }

       // 向 int 类型转换

       static BOOL Castint &DestIFieldInfo *pIDBVariant *pSrc )

       {

              Dest = pSrc->Type() == VariantTypeNull ? 0 : (int)pSrc->GetLong();

              return TRUE;

       }

       // 向 unsignedint 转换

       static BOOL Castunsigned int &DestIFieldInfo *pIDBVariant *pSrc ){ ... }

       // 向 long 类型转换

       static BOOL Castlong &DestIFieldInfo *pIDBVariant *pSrc ){ ... }

       // 向unsignedlong转换

       static BOOL Castunsigned long &DestIFieldInfo *pIDBVariant *pSrc ){ ... }

};

        应该能得看出,我们需要写很多个Cast函数来支持诸如unsigned int、int &,unsigned int &和int &&等等等等int类型和long、double的各种变体。

        那么,来抽取以上Cast函数的共性(Dest = pSrc->Type() ==VariantTypeNull ? 0 : (DestType) pSrc->GetLong() ;)将其写为一个函数,并使用类型列表保存其可转向的类型,然后泛化Cast函数在其中检查目的类型是否存在于可转向的类型列表中,如果是,则施行转换,否则,返回FALSE(表示转换失败)。

        由于时间和篇幅,我直接粘贴代码并作少量解释。如果仍然不懂,可来寻求帮助;(Q我)。(注意:以下转换器的名称改为VariantCast,不再沿用CustomizeVariantCas)

/** TupleInclude

       检查_Tuple 中是否有个元素的类型为 _Dty。注意:TupleInclude会退化_Dty类型后再作检查。

       如果被检查的类型(_Dty)is_integral验证成立,还会去除类型的 unsigned 标志。       */

templatetypename _Dty,

       typename _Tuple,

       size_t n,

       bool IsIntegral >

struct TupleIncludeBase

{

       enum{

              value = TupleIncludeBase_Dty_Tuplen - 1, IsIntegral >::value ?

              true :

              is_samedecay<_Dty>::typetuple_elementn - 1, _Tuple>::type >::value

       };

};

templatetypename _Dty,

       typename _Tuple,

       bool IsIntegral >

struct TupleIncludeBase < _Dty_Tuple, 0, IsIntegral >

{

       enumvalue = false };

};

 

templatetypename _Dty,

       typename _Tuple,

       size_t n >

struct TupleIncludeBase < _Dty_Tuplentrue >

{

       enum{

              value = TupleIncludeBase_Dty_Tuplen - 1, true >::value ?

              true :

              is_samedecay<make_signed<_Dty >::type >::typetuple_elementn - 1, _Tuple>::type >::value

       };

};

templatetypename _Dty,

       typename _Tuple >

struct TupleIncludeBase < _Dty_Tuple, 0, true >

{

       enumvalue = false };

};

 

templatetypename _Dty,

       typename _Tuple,

       size_t n >

struct TupleInclude

{

       enum{

              value = TupleIncludeBase_Dty_Tuplenis_integral_Dty >::value && !is_samebool_Dty >::value >::value

       };

};

templatetypename _Dty,

       typename _Tuple >

struct TupleInclude < _Dty_Tuple, 0 >

{

       enumvalue = false };

};

 

// 用tuple仿制的类型列表。

templatetypename ..._Types > struct TypesList

{

       typedef tuple_Types... > type;

       enumlength = sizeof...(_Types) };

};

 

templateVariantType VariantTypeFlag > struct VariantCast

{

#if defined_DEBUG ) /* 如果没有以特定源类型特化 VariantCast,则在Release编译时会失败,而Debug时会断言失败以便调试 */

       templatetypename _Dty > STATIC BOOL Cast_Dty &, IFieldInfo *, IDBVariant * )

       {

              // 你必须为VariantTypeFlags 向 _Dty 类型的转换特化VariantCast类或重载Cast函数。

              assertFALSE );

              return FALSE;

       }

#endif

};

// 如果调用者使用 BoolCast<false>::Cast(...),则会调用此泛化版的 BoolCast中的Cast函数

templatebool NotTrue > struct  BoolCast

{

       templatetypename _Dty > STATIC BOOL Cast_Dty &, IFieldInfo *, IDBVariant * )

       {

              // 所有 bool 型不能转向的目标类型都会被送到这里。

              // 自行实现 bool 向 _Dty 的转换。

              assertFALSE );

              return FALSE;

       }

};

// 如果调用者使用BoolCast<true>::Cast(...),则会调用此特化版的 BoolCast中的Cast函数

template<> struct BoolCast < true >

{

       templatetypename _Dty > STATIC BOOL Cast_Dty &DestIFieldInfo *pSrcInfoIDBVariant *pSrc )

       {

              assertpSrcInfo->Type() == FieldTypeBit );

              assertpSrc->Type() == VariantTypeBool || pSrc->Type() == VariantTypeNull );

 

              CONST BOOL bSrcpSrc->Type() == VariantTypeNull ? FALSE : pSrc->GetBool() );

              Dest = !!bSrc;

 

              return TRUE;

       }

};

 

// 特化的 VariantCast,实现由 VariantTypeBool 向目的类型的转换。

template<> struct VariantCast < VariantTypeBool >

{

       templatetypename _Dty > STATIC BOOL Cast_Dty &DestIFieldInfo *pSrcInfoIDBVariant *pSrc )

       {

              // bool 型几乎可以向所有基础类型转换,但向float或double转换显然是不合理的,应该不会有人写出:if(!fFloat)..

              // 这样的代码,所以,这里只允许向以下几种类型转换。

              // 定义一个类型列表,类型列表中包含5种类型,分别为 bool, char, int, long,__int64       

              typedef TypesListboolcharintlong__int64 > SupportedTypes;

              // 使用TupleInclude 检查 _Dty是否被包含在以上类型列表中(TupleInclude对类型检查时会同时检查类型的变体,如检查int时还同时检查unsigned int, int&, int&& 等)

              // 如果TupleInclude检查到类型列表中包含_Dty,则其成员value值为true,否则为false,可据此让编译器选择该调用哪个(泛化还是特化)版本的BoolCase中的Cast函数。

              return BoolCastTupleInclude_DtySupportedTypes::typeSupportedTypes::length >::value >::CastDestpSrcInfopSrc );

       }

};

        至此,实现了 VariantTypeBool 向 bool、char、unsigned char、unsigned char &、unsignedchar &&、char &、char &&, int, int &, unsigned int, ...等等等等数十种类型的转换。那么,据此,可以继续以相同方式实现向其它类型的转换,本文不再赘述。

原创粉丝点击