Traits技术:类型的if-else-then(STL核心技术之一)

Traits: 类型的else-if-then机制

Andrei Alexandrescu

Andrei Alexandrescu在位于华盛顿州西雅图市的RealNetworks公司中任开发经理。

什么是traits,为什么人们把它认为是C++ Generic Programming的重要技术?

简短截说,traits如此重要,是因为此项技术允许系统在编译时根据类型作一些决断,
就好像在运行时根据值来作出决断一样。更进一步,此技术遵循“另增一个间接层”
的谚语,解决了不少软件工程问题,traits使您能根据其产生的背景(context)
来作出抉择。这样最终的代码就变得清晰易读,容易维护。如果你正确运用了traits
技术,你就能在不付出任何性能和安全代价的同时得到这些好处,或者能够契合其他
解决方案上的需求。

例子:Traits不仅是泛型程序设计的核心工具,而且我希望以下的例子能够使你相信,
在非常特定的问题中,它也是很有用的。

假设你现在正在编写一个关系数据库应用程序。可能您一开始用数据库供应商提供的
API库来进行反问数据库的操作。但是理所当然的,不久之后你会感到不得不写一些
包装函数来组织那些原始的API,一方面是为了简洁,另一方面也可以更好地适应
你手上的任务。这就是生活的乐趣所在,不是吗?

一个典型的API是这样的:提供一个基本的方法用来把游标(cursor, 一个行集和或
者查询结果)处的原始数据传送到内存中。现在我们来写一个高级的函数,用来把某
一列的值取出来,同时避免暴露底层的细节。这个函数可能会是这个样子:
(假想的DB API用db或DB开头)

// Example 1: Wrapping a raw cursor int fetch
// operation.
// Fetch an integer from the
//     cursor "cr"
//     at column "col"
//     in the value "val"
void FetchIntField(db_cursor& cr,
    unsigned int col, int& val)
{
    // Verify type match
    if (cr.column_type[col] != DB_INTEGER)
        throw std::runtime_error(
        "Column type mismatch");
    // Do the fetch
    db_integer temp;
    if (!db_access_column(&cr, col))
        throw std::runtime_error(
        "Cannot transfer data");
    memcpy(&temp, cr.column_data[col],
        sizeof(temp));
    // Required by the DB API for cleanup
    db_release_column(&cr, col);
    // Convert from the database native type to int
    val = static_cast<int>(temp);
}

这种接口函数我们所有人都可能不得不在某个时候写上一遍,它不好对付但又非常重
要,处理了大量细节,而且这还只是一个简单的例子。FetchIntField抽象,提供了
高一层次的功能,它能够从游标处取得一个整数,不必再担心那些纷繁的细节。

既然这个函数如此有用,我们当然希望尽可能重用它。但是怎么做?一个很重要的泛化步骤就是让这个函数能够处理int之外的类型。为了做到这一点,我们得仔细考虑代码中跟int类型相关的部分。但首先,DB_INTEGER和db_integer是什么意思,它们是打哪儿来的?是这样,关系数据库供应商通常随API提供一些type-mapping helpers,为其所支持的每种类型和简单的结构定义一个符号常量或者typedef,把数据库类型对应到C/C++类型上。

下面是一段假想的数据库API头文件:

#define DB_INTEGER 1
#define DB_STRING 2
#define DB_CURRENCY 3
...
typedef long int db_integer;
typedef char     db_string[255];
typedef struct {
    int integral_part;
    unsigned char fractionary_part;
} db_currency;
...

我们试着来写一个FetchDoubleField函数,作为走向泛型化的第一步。此函数从游标处得到一个double值。数据库本身提供的类型映像(type mapping)是db_currency,但是我们希望能用double的形式来操作。FetchDoubleField看上去跟FetchIntField很相似,简直就是孪生兄弟。例2:

// Example 2: Wrapping a raw cursor double fetch operation.
//
void FetchDoubleField(db_cursor& cr, unsigned int col, double& val)
{

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值