C++“准”标准库Boost学习指南(6):Boost.Any

Boost.Any

Any库支持类型安全地存储和获取任意类型的值。当你需要一个可变的类型时,有三种可能的解决方案:
  • 无限制的类型,如 void*. 这种方法不可能是类型安全的,应该象逃避灾难一样避免它。
  • 可变的类型,即支持多种类型的存储和获取的类型。
  • 支持转换的类型,如字符串类型与整数类型之间的转换。

Any实现了第二种方案,一个基于值的可变化的类型,无限可能的类型。这个库通常用于把不同类型的东西存储到标准库的容器中。

Any 库如何改进你的程序?
  • 任意类型的类型安全存储以及安全的取回
  • 在标准库容器中存放不同类型的方法
  • 可以在无须知道类型的情况下传送类型

Any库提供一个类型, any, 它允许存入任意类型且稍后取回,而不损失类型安全性。它有点象是可变类型的化合物:它可以持有任意类型,但你必须知道类型才能取回值。有很多次你想在同一个容器中存入互不相关的类型。有很多次某些代码只想从一个指针向另一个指针传送数据,而不关心数据的类型。从表面看,这些事情很容易做。它们可以通过一个无类的类型来实现,如 void*. 它们也可以通过使用一个含有不同类型的union来实现。有很多可变类型通过一些类型标识机制来实现。不幸的是,所有这些都缺乏类型安全性,而只有在最可控的情形下我们才应该故意绕过类型系统。标准库的容器是要通过它们所包含的类型来特化的,这意味着不可能把不同类型的元素存入容器之内。幸运的是,解决的方案不一定要 void*, 因为 Any 库允许你将存入不同的类型而稍后取回。没有办法在不知道实际类型的情况下取回存入的值,类型安全从而得到保证。

在设计框架时,不可能预先知道哪些类型要和框架类一起使用。一个常见的方法是,要求框架的使用者遵守某种接口,或者从框架所提供的某个基类进行派生。这是合理的,因为框架可能需要与不同的高级类进行通信才能使用。但是也存在这样的情形,框架对于存入或接受的类型无须(或不能)知道任何相关信息。不要绕过类型系统去使用 void* 方法,框架可以使用 any 。

Any 如何适用于标准库?

Any的一个重要特性是,它提供了存储不同类型的对象到标准库容器中的能力。它也是一种可变数据类型,这正是C++标准库非常需要而又缺乏的。


Boost.Any

头文件: "boost/any.hpp"

类 any 允许对任意类型进行类型安全的存储和取回。不象无类类型,any 保存了类型信息,并且不会让你在不知道正确类型的情况下获得存入的值。当然,有办法可以让你询问关于类型的信息,也有测试保存的值的方法,但最终,调用者必须知道在 any 对象中的值的真实类型,否则不能访问any。可以把 any 看作为上锁的安全性。没有正确的钥匙,你不能进入其中。any 对它所保存的类型有以下要求:

  • CopyConstructible 它必须可以复制这个类型
  • Non-throwing destructor 就象所有析构函数应该的那样!
  • Assignable 为了保证强异常安全(不符合可赋值要求的类型也可以用于 any, 但没有强异常安全的保证)

以下是 any 的公有接口:

namespace boost {

  class any {
  public:
    any();
    any(const any&);

    template<typename ValueType>
     any(const ValueType&);

    ~any();

    any& swap(any &);
    any& operator=(const any&);

    template<typename ValueType>
     any& operator=(const ValueType&);

    bool empty() const;
    const std::type_info& type() const;
  };
}


成员函数

  1. any();
缺省构造函数创建一个空的 any 实例,即一个不含有值的 any。当然,你无法从一个空的any中取回值,因为没有值存在。
  1. any(const any& other);
创建一个已有 any 对象的独立拷贝。other 中含有的值被复制并存入 this.
  1. template<typename ValueType> any(const ValueType&);
这个模板构造函数存入一个传入的ValueType类型参数的拷贝。参数是一个 const 引用,因此传入一个临时对象来存入any是合法的。注意,该构造函数不是 explicit 的,如果是的话, any 会难以使用,而且也不会增加安全性。
  1. ~any();
析构函数销毁含有的值,但注意,由于对一个裸指针的析构不会调用operator delete 或 operator delete[] ,所以在any中使用指针时,你应该把裸指针包装成一个象 shared_ptr 那样的智能指针。
  1. any& swap(any& other);
交换存在两个 any 对象中的值。
  1. any& operator=(const any& other);
如果any实例非空,则丢弃所存放的值,并存入other值的拷贝。
  1. template<typename ValueType>
  2.   any& operator=(const ValueType& value);
如果any实例非空,则丢弃所存放的值,并存入 value 的一份拷贝,value可以是任意符合any要求的类型。
  1. bool empty() const;
给出any实例当前是否有值,不管是什么值。因而,当any持有一个指针时,即使该指针值为空,则 empty 也返回 false 。
  1. const std::type_info& type() const;
给出所存值的类型。如果 any 为空,则类型为 void.

普通函数
  1. template<typename ValueType>
  2.   ValueType any_cast(const any& operand);
any_cast 让你访问any中存放的值。参数为需要取回值的 any 对象。如果类型 ValueType 与所存值不符,any 抛出一个 bad_any_cast 异常。请注意,这个语法有点象 dynamic_cast.
  1. template<typename ValueType>
  2.   const ValueType* any_cast(const any* operand);
any_cast 的一个重载,接受一个指向 any 的指针,并返回一个指向所存值的指针。如果 any 中的类型不是 ValueType, 则返回一个空指针。请再次注意,这个语法也有点象 dynamic_cast.
  1. template<typename ValueType>
  2.   ValueType* any_cast(any* operand);
any_cast 的另一个重载,与前一个版本相似,但前一个版本使用 const 指针的参数并返回 const 指针,这个版本则不是。

异常

bad_any_cast

当试图将一个any对象转换为该对象所存类型以外的其它类型,将抛出该异常。bad_any_cast 派生自 std::bad_cast. 注意,使用指针参数调用 any_cast 时,将不抛出异常(类似于对指针使用 dynamic_cast 时返回空指针一样),反之对引用类型使用 dynamic_cast 则会在失败时抛出异常。


用法

Any库定义在名字空间 boost 内。你要用类 any 来保存值,用模板函数 any_cast 来取回存放的值。为了使用 any, 要包含头文件 "boost/any.hpp". 创建一个可以存放任意值的实例是很容易的。

  1. boost::any a;
把任意类型的值赋给它也很容易。

a=std::string("A string");
a=42;
a=3.1415;


any几乎可以接受任何东西!但是,为了真正能使用存放在any中的值,我们需要取回它,对吧?为此,我们需要知道这个值的类型。

  1. std::string s=boost::any_cast<std::string>(a);
  2. // 抛出 boost::bad_any_cast.
这显然不行;因为当前的 a 所持的是一个 double, any_cast 抛出一个 bad_any_cast 异常。以下这样则可以。
  1. double d=boost::any_cast<double>(a);
any 只允许你在知道类型的前提下访问它的值,这是很明智的。对于这个库,典型情况下你只需记住两件事:类 any, 用于存放值,还有模板函数 any_cast, 用于取回值。

任意的东西!

考虑三个类,A, B, 和 C, 它们没有共同的基类,而我们想把它们存入一个 std::vector. 如果它们没有共同基类,看起来我们不得不把它们当成 void* 来保存,对吗?唔,not any more (相关语,没有更多的了),因为类型 any 没有改变对所存值的类型的依赖。以下代码示范了如何解决这个问题。

#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "boost/any.hpp"

class A {
public:
  void some_function() { std::cout << "A::some_function()\n"; }
};

class B {
public:
  void some_function() { std::cout << "B::some_function()\n"; }
};

class C {
public:
  void some_function() { std::cout << "C::some_function()\n"; }
};

int main() {
  std::cout << "Example of using any.\n\n";

  std::vector<boost::any> store_anything;

  store_anything.push_back(A());
  store_anything.push_back(B());
  store_anything.push_back(C());

  // 我们再来,再加一些别的东西
  store_anything.push_back(std::string("This is fantastic! "));
  store_anything.push_back(3);
  store_anything.push_back(std::make_pair(true, 7.92));

  v
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值