如何为 CIOWrapper::Select 编写类型转换器
来源:互联网 发布:人物简笔画软件 编辑:程序博客网 时间:2024/06/04 18:14
如果你不知道这篇文章在说什么,请前往 http://blog.csdn.net/passfuhao/article/details/76545332,阅读本文的前半部分。
注:
这算得上是DBIOWrapper的高级用法,需要较深的C++基础。绝大多数时候使用DBIOWrapper的默认实现既可,所以,你可能并非真的需要知悉以下内容。
我仍然认为有必要解释一下如何为Select编写类型转换器(默认的转换器是VariantCast),因为转换器是DBIOWrapper的复杂和缺陷所在。另外我还认为一定会有人需要诸如“将数值转换为字符串”的诉求。
Select函数的声名如下:
template< template< VariantType > class CastType = VariantCast, typename ..._Types > BOOL Select( __out _Types&... Args );
Select接受一个模板类(或模板结构)类型模板参数(CastType)作为转换器,和数个任意类型的输出参数,CastType的声名形式必须能够接受一个VariantType型的数值型模板参数作为源类型(参见表1.4中的“源类型”),其声名可能如下:
template< typename VariantType > struct CustomizeVariantCast{ ... };
CustomizeVariantCast结构的模板参数 VariantType 会被实例化为源类型,即:调用其成员函数Cast 时传递的第三个参数IDBVariant对象中存储的数据的类型。
CastType模板类(或结构)中还必须提供形如以下的名为Cast的静态成员函数:
static BOOL Cast( DestType &Dest, IFieldInfo *pFieldInfo, IDBVariant *pSrc );
其中 DestType 是用户调用Select函数时传递的参数类型,Cast函数负责将 pSrc中存储的数据转换为DestType类型并存储到Dest变量中,因为调用Select时可能会传递多个不同类型的参数,所以Cast函数也必须能接受多种不同类型的Dest参数,那么,其声名更可能是模板,如下:
template< typename _Dty > static BOOL Cast( _Dty &Dest, IFieldInfo *p1, IDBVariant * pSrc );
然而,这种模板化的版本中,它的模板参数_Dty可能是任意类型,我们不可能在这一个模板化的函数中根据_Dty 的不同而实现出转换,所以仍然无法为此版Cast编写实现。那么,我们需要对Cast函数特化,实现由IDBVariant向不同类型转换时的不同处理。
template<> static BOOL( int &Dest, IFieldInfo *p1, IDBVariant * pSrc );
template<> static BOOL( double &Dest, IFieldInfo *p1, IDBVariant * pSrc );
template<> static BOOL( __int64 &Dest, IFieldInfo *p1, IDBVariant * pSrc );
还可以通过重载来实现Cast函数,如下:
static BOOL( int &Dest, IFieldInfo *p1, IDBVariant *pSrc );
static BOOL( double &Dest, IFieldInfo *p1, IDBVariant *pSrc );
static BOOL( __int64 &Dest, ...... );
等等等等的各种重载。
当然,我们几乎可以肯定,并不是所有IDBVariant(pSrc )的类型(源类型)都可以向任何目的类型转换,例如:IDBVariant(pSrc)的类型为VariantTypeAString时,显然无法向char类型转换。所以,我们有了转换原则:只允许类型升宽,但不允许收窄(如,int可以向double转换,反之不行),这也是Select函数默认情况下使用的转换器(VariantCast)所施行的原则。
另外,由于我们不应该把所有的源类型向目的类型的转换写在一个(转换器)类(或结构)中,所以,我们还需特化转换器,否则,我们大概会写出以下这样的代码:
template< typename VariantType> struct CustomizeVariantCast
{
static BOOL Cast( double &Dest, IFieldInfo *p, IDBVariant *pSrc )
{
if( pSrc->Type() == VariantTypeLong )
{
// 实现转换
}
else if( pSrc->Type() == VariantTypeFloat )
{
// 实现转换
}
else if( pSrc->Type() == VariantTypeAString )
{
// 报告错误并返回FALSE
return FALSE;
}
...
}
};
主要问题是 pSrc->Type() 会返回所有可能的源类型标识,那么各种源类型向double 类型的转换全部混在一起导致代码混乱而且需要花费运行时间,所以,特化转换器类(或结构)是个合理需求,做法如下:
template<> struct CustomizeVariantCas < VariantTypeLong > /* 仅当pSrc->Type() 返回 VariantTypeLong时调用此结构中的 Cast 成员函数。*/
{
template< typename _Dty > static BOOL Cast( _Dty &Dest, IFieldInfo *p, IDBVariant *pSrc )
{
printf( "不支持向%s类型转换\n", typeid(_Dty).name() );
return FALSE; /* 不支持向 _Dty类型转换 */
}
// 实现向double类型转换
static BOOL Cast( double &Dest, IFieldInfo *p, IDBVariant *pSrc )
{
// pSrc->Type()返回VariantTypeNull的原因是 pSrc存储的对应数据库,表的单元的值为Null。
Dest = pSrc->Type() == VariantTypeNull ? 0 : (double)pSrc->GetLong();
return TRUE;
}
// 向 int 类型转换
static BOOL Cast( int &Dest, IFieldInfo *p, IDBVariant *pSrc )
{
Dest = pSrc->Type() == VariantTypeNull ? 0 : (int)pSrc->GetLong();
return TRUE;
}
// 向 unsignedint 转换
static BOOL Cast( unsigned int &Dest, IFieldInfo *p, IDBVariant *pSrc ){ ... }
// 向 long 类型转换
static BOOL Cast( long &Dest, IFieldInfo *p, IDBVariant *pSrc ){ ... }
// 向unsignedlong转换
static BOOL Cast( unsigned long &Dest, IFieldInfo *p, IDBVariant *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 标志。 */
template< typename _Dty,
typename _Tuple,
size_t n,
bool IsIntegral >
struct TupleIncludeBase
{
enum{
value = TupleIncludeBase< _Dty, _Tuple, n - 1, IsIntegral >::value ?
true :
is_same< decay<_Dty>::type, tuple_element< n - 1, _Tuple>::type >::value
};
};
template< typename _Dty,
typename _Tuple,
bool IsIntegral >
struct TupleIncludeBase < _Dty, _Tuple, 0, IsIntegral >
{
enum{ value = false };
};
template< typename _Dty,
typename _Tuple,
size_t n >
struct TupleIncludeBase < _Dty, _Tuple, n, true >
{
enum{
value = TupleIncludeBase< _Dty, _Tuple, n - 1, true >::value ?
true :
is_same< decay<make_signed<_Dty >::type >::type, tuple_element< n - 1, _Tuple>::type >::value
};
};
template< typename _Dty,
typename _Tuple >
struct TupleIncludeBase < _Dty, _Tuple, 0, true >
{
enum{ value = false };
};
template< typename _Dty,
typename _Tuple,
size_t n >
struct TupleInclude
{
enum{
value = TupleIncludeBase< _Dty, _Tuple, n, is_integral< _Dty >::value && !is_same< bool, _Dty >::value >::value
};
};
template< typename _Dty,
typename _Tuple >
struct TupleInclude < _Dty, _Tuple, 0 >
{
enum{ value = false };
};
// 用tuple仿制的类型列表。
template< typename ..._Types > struct TypesList
{
typedef tuple< _Types... > type;
enum{ length = sizeof...(_Types) };
};
template< VariantType VariantTypeFlag > struct VariantCast
{
#if defined( _DEBUG ) /* 如果没有以特定源类型特化 VariantCast,则在Release编译时会失败,而Debug时会断言失败以便调试 */
template< typename _Dty > STATIC BOOL Cast( _Dty &, IFieldInfo *, IDBVariant * )
{
// 你必须为VariantTypeFlags 向 _Dty 类型的转换特化VariantCast类或重载Cast函数。
assert( FALSE );
return FALSE;
}
#endif
};
// 如果调用者使用 BoolCast<false>::Cast(...),则会调用此泛化版的 BoolCast中的Cast函数
template< bool NotTrue > struct BoolCast
{
template< typename _Dty > STATIC BOOL Cast( _Dty &, IFieldInfo *, IDBVariant * )
{
// 所有 bool 型不能转向的目标类型都会被送到这里。
// 自行实现 bool 向 _Dty 的转换。
assert( FALSE );
return FALSE;
}
};
// 如果调用者使用BoolCast<true>::Cast(...),则会调用此特化版的 BoolCast中的Cast函数
template<> struct BoolCast < true >
{
template< typename _Dty > STATIC BOOL Cast( _Dty &Dest, IFieldInfo *pSrcInfo, IDBVariant *pSrc )
{
assert( pSrcInfo->Type() == FieldTypeBit );
assert( pSrc->Type() == VariantTypeBool || pSrc->Type() == VariantTypeNull );
CONST BOOL bSrc( pSrc->Type() == VariantTypeNull ? FALSE : pSrc->GetBool() );
Dest = !!bSrc;
return TRUE;
}
};
// 特化的 VariantCast,实现由 VariantTypeBool 向目的类型的转换。
template<> struct VariantCast < VariantTypeBool >
{
template< typename _Dty > STATIC BOOL Cast( _Dty &Dest, IFieldInfo *pSrcInfo, IDBVariant *pSrc )
{
// bool 型几乎可以向所有基础类型转换,但向float或double转换显然是不合理的,应该不会有人写出:if(!fFloat)..
// 这样的代码,所以,这里只允许向以下几种类型转换。
// 定义一个类型列表,类型列表中包含5种类型,分别为 bool, char, int, long,__int64
typedef TypesList< bool, char, int, long, __int64 > SupportedTypes;
// 使用TupleInclude 检查 _Dty是否被包含在以上类型列表中(TupleInclude对类型检查时会同时检查类型的变体,如检查int时还同时检查unsigned int, int&, int&& 等)
// 如果TupleInclude检查到类型列表中包含_Dty,则其成员value值为true,否则为false,可据此让编译器选择该调用哪个(泛化还是特化)版本的BoolCase中的Cast函数。
return BoolCast< TupleInclude< _Dty, SupportedTypes::type, SupportedTypes::length >::value >::Cast( Dest, pSrcInfo, pSrc );
}
};
至此,实现了 VariantTypeBool 向 bool、char、unsigned char、unsigned char &、unsignedchar &&、char &、char &&, int, int &, unsigned int, ...等等等等数十种类型的转换。那么,据此,可以继续以相同方式实现向其它类型的转换,本文不再赘述。
- 如何为 CIOWrapper::Select 编写类型转换器
- pdf转换器如何切换语言类型
- Hql的select 语句返回Ilist<object[]>类型,如何转换为映射类型
- 类型转换器
- 类型转换器
- 类型转换器
- 类型转换器
- 类型转换器
- 为struts2自定义类型转换器:Date的转换
- Spring Boot使用全局类型转换器(全局日期转换器为例)
- mybatis 类型类型转换器
- 如何借助转换器将PDF转换为PPT
- select 条件变量为字符串类型
- 如何为thunderbird编写插件
- Struts2类型转换器配置
- C#通用类型转换器
- Struts2的类型转换器
- Struts 2 类型转换器
- Java 并发开发:Lock 框架详解
- 模块化操作
- 数据库原理—超键、候选键、主键、外键
- sublime插件html-css-js Prettify 实现代码格式化
- POJ
- 如何为 CIOWrapper::Select 编写类型转换器
- 31-依赖注入-2
- 消息队列探秘 – RabbitMQ 消息队列介绍
- 编译器之乱
- 32-路由
- 生产环境 hadoop集群监控工具--ganglia的搭建(YUM的方式)
- 文件上传检测的基本思路
- 33-路由设置对象
- 哥德巴赫猜想的实现