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_了。