variant有點類似於C++的聯合體union,但是它比union強大,union只能容納原始類型,variant可以容納任意類型
源代碼看了蠻久,沒太看懂,這就是模板的壞處了
簡單看下使用舉例
class CTest
{
char szTest_[40];
};
typedef variant<int, float, string, CTest> var_t;
var_t也相當於一個聯合體,可以容納三個中的一個,當然內存大是其中一個最大的。另外還得加上一些variant自己的大小,var_t測試的大小是44
STATIC_ASSERT(sizeof(variant1) == 44);
賦值也很簡單
CTest aa;
var_t variant1(aa);
variant1 = 10;
直接使用等號,類型最匹配的即可。
訪問與any類似
try
{
float f1 = get<float>(variant1);
}
catch(boost::bad_get&)
{
}
轉換不成功就會拋出異常,另外它也可以通過轉換爲指針保證不會拋出異常的方式
// 也可以轉換成指針,轉換成指針不會拋出異常,但是如果類型不匹配指針指針所值的內容是
float* pFloat=boost::get<float>(&variant1);
CTest* pTest = boost::get<CTest>(&variant1);
int* pInt = boost::get<int>(&variant1);
assert(NULL == pFloat && NULL == pTest && NULL != pInt && (10 == *pInt));
另外它還提供了一種更安全的訪問方式。需要繼承自stati_visitor,static_visitor的默認模板方式是void,如果是int,operator()的返回類型就需要也使用int
class var_print: public static_visitor<>
{
public:
template<typename T>
void operator()(T& i) const
{
}
template<>
void operator()(double& i) const
{
// do something for i
}
template<>
void operator()(int& i) const
{
}
template<>
void operator()(CTest& i) const
{
}
};
訪問
var_print vp;
apply_visitor(vp, variant1);
這樣variant1就會安全的轉換到對應的函數重載中了。對相應的變量執行相關操作了。
裏面的實現大概猜到一些,variant存儲兩個類型變量
which_t which_;// 該參數表示當前存儲的值是哪個類型
storage_t storage_;// 該參數是存儲真正值的變量,在初始化的時候會分配內存,當然是根據variant中幾個模板參數最大的一個內存進行分配的。
然後賦值的過程
template <typename T>
variant(T& operand)
{
convert_construct(operand, 1L); // 拷貝賦值
}
template <typename T>
void convert_construct(
T& operand
, int
, mpl::false_ = mpl::false_() // is_foreign_variant
)
{
// NOTE TO USER :
// Compile error here indicates that the given type is not
// unambiguously convertible to one of the variant's types
// (or that no conversion exists).
//
indicate_which(
initializer::initialize(
storage_.address()
, operand
)
);
}
// 調用initializer::initialize,然後將返回值賦給whtich_
void indicate_which(int which_arg) BOOST_NOEXCEPT
{
which_ = static_cast<which_t>( which_arg );
}
調用initializer::initialize的過程
static int initialize(void* dest, param_T operand)
{
typedef typename boost::detail::make_reference_content<
recursive_enabled_T
>::type internal_T;
new(dest) internal_T(operand);
return BOOST_MPL_AUX_VALUE_WKND(index)::value; // which
}
是在storage_的地址的地方調用new(dest) internal_T(operand);。拷貝構造函數,dest的地址就是storage_address(),operand就是賦值的那個值。此處value是怎麼取的沒太看懂。反正就賦值給了which_了。