Boost::Any

一 Boost::Any

    很多时候我们想有一种可以代表任何类型的类型,比如像纯面向对象语言java或.net中的Object类型,但是对于C++本身并没有这样一个基类,所以我们如果要解决这类问题,首先我们考虑的是使用基类的指针,这能够解决以部分问题,但是更多的我们可以求助于void*,使用void*的缺点就是丢失了类型信息和缺乏类型安全。

    幸好的是在boost中有boost::Any为我们提供了类似java或.net中的object类型,boost::Any能够代表任意类型,实现任意类型的类型安全存储以及安全的取回,常用在将不同类型的对象存储在标准容器中。

二 源码剖析

   源码: 

 namespace  boost  {
  class bad_any_cast;
  class any;
  template<typename T> T any_cast(any &);
  template<typename T> T any_cast(const any &);
  template<typename ValueType> const ValueType * any_cast(const any *);
  template<typename ValueType> ValueType * any_cast(any *);
}

   Boost::Any的实现比较简单,Any拥有一个模版构造函数,这使他可以接受任何类型的对象。真正的变量内容被封装在嵌套类类型的成员变量中,并且在嵌套类中使用typeid来记录真正的类型信息。

  1) any& swap(any& other);交换存在两个 any 对象中的值。
  2) any& operator=(const any& other);如果any实例非空,则丢弃所存放的值,并存入other值的拷贝。
  3)template<typename ValueType>  any& operator=(const ValueType& value);如果any实例非空,则丢弃所存放的值,并存入 value 的一份拷贝,value可以是任意符合any要求的类型。
  4) bool empty() const;给出any实例当前是否有值,不管是什么值。因而,当any持有一个指针时,即使该指针值为空,则 empty也返回 false 。
  5) const std::type_info& type() const;给出所存值的类型。如果 any 为空,则类型为 void.
  6) any_cast()将any类型转化为真实的类型,如果是指针返回的可能是空指针,如果非指针,则可能会抛出异常。

三 实例

1)简单实例以及调用常用的成员函数:

#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"; 
    }
} ;

 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
    {   
        try 
        {     
            std::cout << boost::any_cast<std::string>(a) << '/n';   
        }   
        catch(boost::bad_any_cast&) 
        {     
            std::cout << "Oops!/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(std::string("This is fantastic! "));  
    store_anything.push_back(3);  
    store_anything.push_back(std::make_pair(true, 7.92));     
    std::for_each(  store_anything.begin(),  store_anything.end(),  print_any);


     std::cout << "Example of using any member functions/n/n"; 
     boost::any a1(100); 
     boost::any a2(std::string("200"));  
     boost::any a3; 
     std::cout << "a3 is "; 
     if (!a3.empty()) 
     {    
         std::cout << "not empty/n "; 
     }  
     std::cout << "empty/n";  
     a1.swap(a2); 
     try 
     {   
         std::string s=boost::any_cast<std::string>(a1); 
         std::cout << "a1 contains a string: " << s << "/n"; 
     } 
     catch(boost::bad_any_cast& e) 
     {  
         std::cout << "I guess a1 doesn't contain a string!/n"; 
     } 
     if (int* p=boost::any_cast<int>(&a2)) 
     {  
         std::cout << "a2 seems to have swapped contents with a1: "      << *p << "/n"; 
     } 
     else
     {    
         std::cout << "Nope, no int in a2/n"; 
     }  
     if (typeid(int)==a2.type()) 
     {    
         std::cout << "a2's type_info equals the type_info of int/n";  
     }

}

2)解决类似与map但是可以映射到各种不同的类型的问题:

#include  < iostream >
#include  < string >
#include  < vector >
#include  < algorithm >
#include  " boost/any.hpp "
 class  property
 {  
    boost::any value_;
    std::string name_;
public:  
    property(const std::string& name,const boost::any& value)  
        : name_(name),value_(value) {}  
    std::string name() const { return name_; } 
    boost::any& value() { return value_; } 
    friend bool operator<(const property& lhs, const property& rhs)
    {return lhs.name_<rhs.name_;}
} ;
 void  print_names( const  property &  p) 
 { 
    std::cout << p.name() << "/n";
}
 int  main() 
 {  
    std::cout << "Example of using any for storing properties./n";
    std::vector<property> properties; 
    properties.push_back(  property("B", 30));
    properties.push_back(  property("A", std::string("Thirty something"))); 
    properties.push_back(property("C", 3.1415));  
    std::sort(properties.begin(),properties.end());
    std::for_each(properties.begin(),  properties.end(),  print_names);
    std::cout << "/n";  
    std::cout <<  boost::any_cast<std::string>(properties[0].value()) << "/n"; 
    std::cout <<  boost::any_cast<int>(properties[1].value()) << "/n"; 
    std::cout <<  boost::any_cast<double>(properties[2].value()) << "/n";    
}

四 注意

1)Any中如果是指针,要注意指针的最后的释放,最好使用shared_ptr来管理。
2)Any中如果是指针,如果Any.isempty()返回false,但是any所包含的指针仍可能是无效的。
3)Any中如果是指针,则在调用any_cast()转化的过程中不会抛出异常,但是如果是一般变量或引用的话,类型不正确会抛出boost::bad_any_cast异常。

五 参考