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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章