Any
库概述
Any
库可以改进程序:
#
对任意的类型提供类型安全(typesafe)的存储和安全的检索;
#
提供了在标准库容器中存放异构类型(heterogeneous type)的方法
#
传递类型所通过的层无须了解任何该类型的信息.
Any
库提供一个类型:any,它允许对任意的类型进行存储,以便稍后进行检索,而且还不损失类型的安全性.很多情况下,我们可能希望在同一个容器中存储互不相关的类型.还有很多情况下,某些特定的代码仅仅关心从一个点到另一个点传递数据的方式,而不关心数据的类型.表面上看,这些事情很容易做.它们可以通过一个诸如void *的无差别类型来实现.同样,它们还可以通过使用一个有差别的联合(discriminated union)来实现.另外,有许多变体类型都通过一些类型标记机制来实现的.然而,所有这些实现方式都缺乏类型安全性,而且只有在最可控的情形下才有可能故意绕过类型系统.标准库的容器对它们所包含的类型进行参数化,因此对这些容器中存储异构类型的元素提出了一个看上去似乎不可能实现的挑战.幸运的是,解决方案不一定必须使用void *,因为Any库允许存储不同类型的对象用于后续的检索.但是还是无法在不了解实际的情况下检索所存储的值,类型安全从而得到保证.
Any
库的一个重要特性就是它提供了在标准容器中存储异构类型对象的能力.另外,它还是一种变体数据类型(variant data type).而这正是C++标准库非常需要但又缺乏的数据类型.
Any
类
类any
允许对任意的类型进行类型安全的存储和检索
.
与无差别的类型不同
,any
类保存了类型的信息
,
而且实际上还不不允许在不知道正确类型的情况下获取所存储的值
.
当然
,
若要查询类型的信息和测试所保存的值的可选项
,
办法还是有的
.
但是最终
,
调用者还是必须知道
any
对象中所存储的值的确切类型
,
否则
any
类就拒绝访问
,
对
any
类来说
,
可以把它看作是一个上了锁的保险箱
,
没有匹配的钥匙
,
就不能进入其中
.any
类对它所存储的类型有以下要求
:
#
可复制构造
(copyConstructible):
它必须可以复制这个类型
.
#
析构函数不抛出异常
:
就象所有的析构函数所应该的那样的
.
#
可赋值
(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<type ValueType&> any & operator=(const ValueType&);
Bool empty() const;
Const std::type_info & type() const;
};
}
Any();
该默认构造函数创建一个
any
类的空实例
,
即一个不含有值的
any
类
.
当然
,
也就无法从一个空的
any
类中检索值
,
因为它里面没有值存在
.
Any(const any & other);
该构造函数创建一个已有的
any
对象的独特副本
.
其中
other
中所包含的值被复制并存储到
this
中
.
Template<typename ValueType> any (const ValueType&);
这个模板化的构造函数存储传递构造函数的类型为
ValueType
的参数的一份副本
.
其中参数是一个
const
引用
,
因此传递一个临时对象以存储到
any
中是合法的
.
注意
,
该构造函数不是显式的
,
那么
any
就回难以使用
,
而且还会影响额外的安全性
.
~any();
该析构函数销毁
any
类所包含的值
,
但要注意
,
因为裸指针
(raw pointer)
的析构并不会对指针调用运算符
delete
或运算
delete[],
所以在
any
中使用指针时
,
应该把裸指针包装在一个诸如
shared_ptr
的智能指针中
.
Any &swap(any & other);
交换两个
any
对象中所存储的值
.
Any & operator = (const any & other);
若
any
实例是非空的
,
那么该函数会丢弃所存储的值
,
然后存入
other
值的一份副本
.
Template<type ValueType&> any & operator=(const ValueType&);
若
any
的实例是非空的
,
那么该函数会丢弃所存储的值
,
然后存入
value
的一份副本
,
其中
value
可以是符合
any
要求的任意类型
.
Bool empty() const;
该函数指示当前是否包含值
,
但不用考虑值的类型
.
因此
,
当
any
中存放指针时
,
即使该指针为空
,empty
函数也要返回
flase.
Const std::type_info & type() const;
该函数指示
any
对象中所存储值的类型
.
若
any
对象为空
,
则该该函数返回的类型为
void.
Any
类中的自由函数
Template <typename ValueType> ValueType any_cast(const any& operand);
Any_cast
函数允许访问
any
中所存储的值
.
其参数为要检索其中的值的
any
对象
.
如果类型
ValueType
与所存储的类型不符
,
则抛出一个类型为
bad_any_cast
的异常
.
这里需要注意的是
,
该函数的语法和
dynamic_cast
函数的语法相似
.
Template <typename ValueType > const ValueType* any_cast(const any *operand);
Any_cast
函数的重载
,
其参数为
any
对象的指针
,
它返回的是一个指向所存储值的指针
.
若
any
对象中的类型不是
ValueType,
那么该重载将返回一个空指针
.
注意
,
该重载函数的语法仍然和
dynamic_cast
函数的语法相似
.
Template <typename ValueType > ValueType* any_cast(any *operand);
Any_cast
函数的另一个重载
,
它与前一个重载版本相似
,
但前一个版本的参数类型和返回类型都使用了
const
限定的指针
,
而这个重载版本则不是这样的
.
异常
Bad_any_cast
当试图将
any
对象转换为该对象所存储类型以外的其他类型时
,
将抛出该异常
.bad_any_cast
异常派生自
std::bad_cast.
需要注意
,
当使用指针参数调用
any_cast
函数时
,
不会抛出异常
(
类似于使用指针型调用
dynamic_cast
函数返回空指针
);
但是
,
当使用引用类型调用
any_cast
函数时
,
则在失败时抛出异常
.
使用用法
Any
库定义在命令空间
boost
中
.
我们可以用类
any
来存储值
,
随后用模板函数
any_cast
来检索所存储的值
.
为了使用
any
类
,
程序中需要包含头文件
”boost/any.cpp”.
创建一个可以存储任意类型的值的实例非常简单
,
如下所示
:
Boost::any a;
对上述实例赋予某个类型的值也很容易
,
如下
:
A = std::string(“A string”);
A = 42;
A = 3.1415;
Any
类几乎可以接受任何类型的值
.
但是
,
为了真正能使用存储在
any
中的值
,
需要检索它
.
为此
,
需要知道这个值的类型
.
Std::string s = boost::any_cast<std::string> (a);
//throws boost::bad_any_cast
上述代码不能得到正确结果
,
这是因为对象
a
中当前所包含的值是
double
类型的
,
这时
any_cast
将抛出一个类型为
bad_any_cast
的异常
.
但下面的代码可得到正确的结果
.
Double d = boost::any_cast<double>(a);
Any
类只有在知道类型的前提下才可以访问它的值
.
一般要牢记
:
类
any
用于存储值
.
而模板函数
any_cast
用于检索存储值
.
现有三个类
A,B,C,
它们没有共同的基类
,
想要把它们存储到一个
std::vector
中
.(any
提供了一种更好的解决方法
,
但是它还没有解决对类型的依赖
.)
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include “boost/any.hpp”
Class A {
Public:
Void some_function() {std::cout<<”A::somefunction()/n”;}
}
Class B {
Public:
Void some_function() {std::cout<<”B::somefunction()/n”;}
}
Class C {
Public:
Void some_function() {std::cout<<”C::somefunction()/n”;}
}
Int main()
{
Std::cout<<”Example of using any./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_apir(true,7.92));
Void print_any(boost::any & a);
//defined later; reports on the value in a
Std::for_each(store_anything.begin(),store_anything.end(),print_any());
}
Void print_any(boost::any & a)
{
If(A *pA = boost::any_cast<A>(&a))
{
pA->some_function();
}
Else if ((B*pB= boost::any_cast<B>(&a))
{
pB->some_function();
}
Else if ((C*pC= boost::any_cast<C>(&a))
{
pC->some_function();
}
Else
{
Try{
Std::cout<<boost::any_cast<std::string>(a)<<endl;
}
Catch(boost::bad_any_cast&){
Std::cout<<”error!/n”;
}
}
}