boost原始碼剖析----boost::any
有的時候我們需要有一個萬能型別來進行一些操作,這時候boost::any就派上用場了。
boost::Any testInt(10);
int val = static_cast<int>(testInt);
用法比較簡單,我們來研究下boost::any是如何實現的。
原理
c++是一個強型別的語言,要實現一個萬能型別可以考慮用void*來儲存資料,然後用型別轉換進行操作,如:
class MyAny{
MyAny(void* input):content_(input){
}
template<typename T>
T any_cast(){return *static_cast<T*>(content_)}
private:
void* content_;
}
但是這樣的寫法有一個明顯的缺點就是型別不安全。
顯然我們可以用template來改進我們的程式:
template<typename T>
class MyAny{
MyAny(T input):content_(input){
}
T any_cast(){return content_;}
private:
T content_;
}
但是這樣我們好像就沒有解決問題:vector<MyAny
為了能寫下如下的程式碼:
vector<MyAny> items;
items.push_bacck(1);
items.push_bacck(2.0);
我們需要我們的萬能型別有如下的行為:
- 對外是一個一般的類,使用者壓入引數的時候不應該關心型別
- 它只是一箇中間層,具體儲存資料的應該是一個模板類(Holder)
- 必須要能有方法支援任意型別的輸入和輸出為任意型別
實現
我們可以通過新增一箇中間層來解決任何問題。
在boost::any中, 通過兩個中間層來達成我們上面的目標, 類any作為對外的介面層,承擔以模板作為引數並提供必要的對外方法。
類placeholder作為介面類,讓any使用。而holder是一個模板類作為類placeholder的實現者, 這樣就避免的any對泛型引數的要求(能自動推到匯出來)。
我這裡模仿了相關的實現,其程式碼結構應該是這樣的:
class Any
{
public:
Any() :holder_(nullptr){}
template<typename ValueType>
Any(const ValueType& val)
: holder_(new Holder<ValueType>(val)){
}
private:
IHolder* holder_;
};
mb_interface IHolder{
}
template<typename ValueType>
class Holder : public IHolder{
public:
Holder(const ValueType& val) : value_(val){
}
}
public:
ValueType value_;
}
其中Holder提供了具體的資料儲存服務,而 Any提供了對外的介面能力。
其中Holder必須提供兩個方法:
mb_interface IHolder{
virtual ~IHolder(){}
virtual const std::type_info& type() const = 0;
virtual IHolder* clone() const = 0;
};
- type()提供了查詢型別的能力
- clone()提供了產生資料的能力
在 Any中, 提供了以下幾個個介面:
bool empty(){
return !holder_;
}
const std::type_info& type() const {
return holder_ ? holder_->type() : typeid(void);
}
Any& operator=(Any rhs){
return swap(rhs);
}
template<typename ValueType>
Any& operator=(const ValueType& val){
return Any(val).swap(*this);
}
判斷是否為空,查詢型別操作,賦值操作
當然必須還有最重要的any_cast操作,我們看其實現:
template<typename ValueType>
ValueType* anyCast(Any* val){
return (val && val->type() == typeid(ValueType))
? &static_cast<Holder<ValueType>*>(val->getHolder())->value_ : 0;
}
template<typename ValueType>
ValueType anyCast(Any& val){
ValueType* rtn = anyCast<ValueType>(&val);
if (!rtn)boost::throw_exception(badAnyCast());
return *rtn;
}
果然好簡單。呵呵~~~
最後添上單元測試,整個程式碼就完善了:
mb::Any testInt(10);
mb::Any testDouble(10.0);
mb::Any testInt2(testInt);
EXPECT_EQ(testInt.empty(), false);
EXPECT_EQ(std::string(testDouble.type().name()), "double");
EXPECT_EQ(std::string(testInt2.type().name()), "int");
int val = mb::anyCast<int>(testInt);
EXPECT_EQ(val, 10);