Boost::Any
一 Boost::Any
很多時候我們想有一種可以代表任何類型的類型,比如像純面向?qū)ο笳Z言java或.net中的Object類型,但是對于C++本身并沒有這樣一個基類,所以我們?nèi)绻鉀Q這類問題,首先我們考慮的是使用基類的指針,這能夠解決以部分問題,但是更多的我們可以求助于void*,使用void*的缺點(diǎn)就是丟失了類型信息和缺乏類型安全。
幸好的是在boost中有boost::Any為我們提供了類似java或.net中的object類型,boost::Any能夠代表任意類型,實(shí)現(xiàn)任意類型的類型安全存儲以及安全的取回,常用在將不同類型的對象存儲在標(biāo)準(zhǔn)容器中。
二 源碼剖析
源碼:

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的實(shí)現(xiàn)比較簡單,Any擁有一個模版構(gòu)造函數(shù),這使他可以接受任何類型的對象。真正的變量內(nèi)容被封裝在嵌套類類型的成員變量中,并且在嵌套類中使用typeid來記錄真正的類型信息。
1) any& swap(any& other);交換存在兩個 any 對象中的值。
2) any& operator=(const any& other);如果any實(shí)例非空,則丟棄所存放的值,并存入other值的拷貝。
3)template<typename ValueType> any& operator=(const ValueType& value);如果any實(shí)例非空,則丟棄所存放的值,并存入 value 的一份拷貝,value可以是任意符合any要求的類型。
4) bool empty() const;給出any實(shí)例當(dāng)前是否有值,不管是什么值。因而,當(dāng)any持有一個指針時,即使該指針值為空,則 empty也返回 false 。
5) const std::type_info& type() const;給出所存值的類型。如果 any 為空,則類型為 void.
6) any_cast()將any類型轉(zhuǎn)化為真實(shí)的類型,如果是指針返回的可能是空指針,如果非指針,則可能會拋出異常。
三 實(shí)例
1)簡單實(shí)例以及調(diào)用常用的成員函數(shù):
#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中如果是指針,則在調(diào)用any_cast()轉(zhuǎn)化的過程中不會拋出異常,但是如果是一般變量或引用的話,類型不正確會拋出boost::bad_any_cast異常。
五 參考
1)Beyond the C++ Standard Library: An Introduction to Boost
2)boost在線document