boost之variant使用

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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值