分享

秘笈4 使用更安全的方式处理存储多个选择类型的容器

 码农书馆 2018-02-28

试想一下,在创建围绕某个SQL数据库接口的一个包装。你决定 boost::any将完全匹配数据库表的一个单元格的要求。其他某个程序员会使用你的类,他的任务将是从数据库中获得行,计算在一行的算术类型的总和。

代码类似于下面这样:

如果编译并运行这个例子,会输出一个正确的答案:

(数据库中算术类型行的合计是:20.1)

还记得阅读operator()的实现时你的想法是什么吗?我猜你的想法是,“double, long, short, unsigned和其他类型怎么办?”将使用你的接口的一个程序员的脑海中也有同样的想法。所以你需要在文档中仔细记录你的cell_t存储的值,或阅读下面章节中描述的更优雅的解决方案。

准备

如果你不熟悉Boost.Variant和Boost.Any库,强烈建议先阅读前面两个秘笈。

做法

Boost.Variant库实现了一个访客编程模式来访问存储的数据,这比通过 boost::get<>获取值安全得多。这种模式迫使程序员处理好每个变体类型,否则代码将编译失败。可以通过boost::apply_visitor函数使用这个模式,这个函数采用访客函数化对象(functional object)作为第一个参数,并用一个变体作为第二个参数。访客函数化对象必须派生自boost::static_visitor<T>类,其中T是被访客返回的一个类型。访客对象必须为变体中存储的每种类型备有重载 operator()。

下面将cell_t类型改为boost::variant<int, float, string>并修改我们的例子:

工作原理

Boost.Variant库在编译时会产生一个大的switch语句,which的每个case将对变体的类型列表中的单个类型调用一个访客。在运行时,可以使用which()得到存储类型的索引,并将跳转到switch语句中正确的case处。某些像这样的东西将为boost::variant<int, float, std::string>产生:

在这里,address()函数返回指向boost::variant<int, float, std::string>内部存储的一个指针。

还有更多

如果将这个例子与这个秘笈的第一个例子比较,将看到boost::variant有以下优点:

知道变量可以存储什么类型。

如果一个SQL接口库的作者添加或修改了一个变体持有的一个类型,会得到一个编译时错误,而不是不正确的行为。

参见

学完第4章的一些秘笈后,就能够使访客对象很通用,因此,即使基础类型变化了,它也有能力正确地工作。

Boost的官方文档中包含更多的例子和Boost.Variant的一些其他功能的描述,可在以下地址获得该资料:http://www./doc/libs/1_53_0/doc/html/variant.html

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多