Take a glance of Boost(1): Any

为什么需要Boost::Any

    如果在C++有让一个变量存储任意类型,人们自然而然会想到void:

void * A = “Test”;

    但是,void并没有很好地完成这项任务。我们看一下下面一段代码:

void * A[3];
    
char * s1 = "Test";
    
int i1 = 5;
    
double d1 = 6.0

    A[
0= s1;
    A[
1= &i1;
    A[
2= &d1; 

    
char * s2 = (char *)A[0];
    
int i2 = *(int *)A[1];           // 1
    int d2 = *(double *)A[2];

    代码的目的很明显,A被当做万能数组来存放任意类型,但是,void的局限性也显现了出来。第一,我们没有办法将一个常量放入数组A,会产生编译错误;第二,我们在取出数组的元素时,我们需要对元素类型进行判断,如果一个人不小心,把1处写成int i2 = *(int *)A[2];,那么,后果需不堪设想,这就是典型的类型安全错误。

    那么,我们如何既能保证类型安全,又能使用“万能容器”呢?这个任务由Boost::Any来完成。

★Boost::Any的使用

    我们首先来看一下使用Boost::Any的例子。

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

    A.push_back((
char *)"Test");                       // 1
    A.push_back(5);
    A.push_back(
6.0); 

    
char * s = boost::any_cast<char *>(A[0]);    // 2
    int i = boost::any_cast<int>(A[1]);               // 3
    double d = boost::any_cast<double>(A[2]); 

    如果我们不小心把2处写成char * s = boost::any_cast<char *>(A[1]),由于boost::any_cast在类型转换时进行了类型检查,这时s将被赋为NULL。如果是值类型(非指针类型,如3 处),若类型检查没通过的话,将会抛出bad_any_cast异常。同时,我们可以很容易地将常量类型赋值给boost::any。注意,1处展示了 boost::any的一个缺点,它不能用来存放数组,这是由编译器无法在编译期动态分配内存的原因。

★Booster::Any源码分析

    我们看一下boost::any代码的一些片断:

// any, 代码经过裁剪,下同

    
class any
    
{
    
public// structors 

        any(); 

        template
<typename ValueType>
        any(
const ValueType & value)
          : content(
new holder<ValueType>(value))
        
{
        }
 

        any(
const any & other); 

        
~any(); 

    
public// modifiers 

        any 
& swap(any & rhs); 

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

        any 
& operator=(any rhs); 

    
public// queries 

        
bool empty() const

        
const std::type_info & type() const
        
{
            
return content ? content->type() : typeid(void);
        }
 

    
private// types 

        
class placeholder
        
{
        
public// structors 

            
virtual ~placeholder(); 

        
public// queries 

            
virtual const std::type_info & type() const = 0

            
virtual placeholder * clone() const = 0

        }


        template
<typename ValueType>
        
class holder : public placeholder
        
{
        
public// structors 

            holder(
const ValueType & value); 

        
public// queries 

            
virtual const std::type_info & type() const
            
{
                
return typeid(ValueType);
            }
 

            
virtual placeholder * clone() const

        
public// representation 

            ValueType held; 

        
private// intentionally left unimplemented
            holder & operator=(const holder &);
        }


    
private// representation 

        template
<typename ValueType>
        friend ValueType 
* any_cast(any *); 

        template
<typename ValueType>
        friend ValueType 
* unsafe_any_cast(any *); 

        placeholder 
* content; 

    }
;

     上面是boost::any的实现,为了方便讲述,我只保留了一些重要的实现,以后也将如此。我们可以看到,boost::any有一个类型为 placeholder的成员content,用来指向存储容器holder。holder派生自placeholder,是一个模板类。用基类指针指向模板子类,这样,any在实例化时就可以不用管存储的类型是什么,而直接把这项工作交给了编译器(注意赋值运算符等操作是模板函数),这就是 boost::any。

    我们看一下boost::any_cast()的实现:

template<typename ValueType>
    ValueType 
* any_cast(any * operand)
    
{
        
return operand && operand->type() == typeid(ValueType)
                    
? &static_cast<any::holder<ValueType> *>(operand->content)->held
                    : 
0;
    }
 

    在实现中我们看到,boost::any_cast()通过使用typeid()来进行类型检查,如果类型不匹配,则返回0(即NULL)。这是boost::any_cast()对指针的特化版本。泛化版本如下:

template<typename ValueType>
    ValueType any_cast(any 
& operand)
    
{
        typedef BOOST_DEDUCED_TYPENAME remove_reference
<ValueType>::type nonref;  // 1  

        nonref 
* result = any_cast<nonref>(&operand);
        
if(!result)
            boost::throw_exception(bad_any_cast());
        
return *result;
    }
 

    泛化版本的boost::any_cast()使用了指针特化版本的boost::any_cast()。在类型不匹配的情况下,抛出bad_any_cast异常。

posted on 2009-05-12 19:45 Benjamin Luo 阅读(218) 评论(0)  编辑 收藏 引用 所属分类: 深入C++


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年5月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

公告

QQ: 191403953 MSN: yiyaman@hotmail.com twitter: http://twitter.com/yiyaman

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

搜索

最新评论

阅读排行榜

评论排行榜