淺談boost.variant的幾種訪問方式

此處輸入圖片的描述

前言

variant類型在C++14並無加入,在cppreference網站上能夠看到該類型將會在C++17加入,若想在不支持C++17的編譯器上使用variant類型,咱們能夠經過boost的variant類型,variant類型能夠表示任意一種類型和any類型有些類似,但仍是有些區別,好比說variant支持的類型需提早定義,而any類型不須要,獲取any類型的值須要給出原始類型,然而variant類型支持多種方式訪問,其中一種就是經過訪問者模式來訪問,是不須要給出原始類型的,下面將淺談variant的幾種訪問方式(我的博客也發表了《淺談boost.variant的幾種訪問方式》)。html

使用boost::get

boost::variant<int, std::string> v;
v = "Hello world";
std::cout << boost::get<std::string>(v) << std::endl;

使用boost::get來訪問,須要給出原始類型,而且這樣作不安全,若類型錯誤,程序將會拋出異常。安全

使用RTTI

void var_print(boost::variant<int, std::string>& v)  
{  
    if (v.type() == typeid(int))  
    {  
        std::cout << boost::get<int>(v) << std::endl;  
    }
    else if (v.type() == typeid(std::string))  
    {  
        std::cout << boost::get<std::string>(v) << std::endl;  
    }  
    // Else do nothing
}  
int main()  
{  
    boost::variant<int, std::string> v;
    v = "Hello world";  
    var_print(v);
    return 0;
}

使用RTTI技術能夠避免類型訪問錯誤而程序異常的狀況,可是這樣作有點不優雅,每增長一個類型,都須要修改if-else結構,而且使用RTTI會對程序性能有必定影響。app

使用訪問者模式

class var_visitor : public boost::static_visitor<void>
{
public:
    void operator()(int& i) const
    {
        std::cout << i << std::endl;
    }

    void operator()(std::string& str) const
    {
        std::cout << str << std::endl;
    }
};
int main()  
{  
    boost::variant<int, std::string> v;
    v = "Hello world";  
    boost::apply_visitor(var_visitor(), v);
    return 0;
}

使用該模式,須要定義一個類並繼承於boost::static_visitor,在類裏面須要重載()操做符,經過boost::apply_visitor來訪問原始類型的值,這樣作仍是有些繁瑣,每增長一個類型,都須要在var_visitor裏面增長一個函數,但比使用RTTI裏面的修改if-else結構好得多,由於使用訪問者模式至少是遵循開放-封閉原則的,即對寫開放,對修改封閉。函數

使用模板函數

class var_visitor : public boost::static_visitor<void>
{
public:
    template<typename T>
    void operator()(T& i) const
    {
        std::cout << i << std::endl;
    }
};
int main()  
{  
    boost::variant<int, std::string> v;
    v = "Hello world";  
    boost::apply_visitor(var_visitor(), v);
    return 0;
}

operator()改爲了模板函數的好處就是不用關心variant支持多少類型。性能

參考資料

boost官網網站

相關文章
相關標籤/搜索