variant類型在C++14並無加入,在cppreference網站上能夠看到該類型將會在C++17加入,若想在不支持C++17的編譯器上使用variant類型,咱們能夠經過boost的variant類型,variant類型能夠表示任意一種類型和any類型有些類似,但仍是有些區別,好比說variant支持的類型需提早定義,而any類型不須要,獲取any類型的值須要給出原始類型,然而variant類型支持多種方式訪問,其中一種就是經過訪問者模式來訪問,是不須要給出原始類型的,下面將淺談variant的幾種訪問方式(我的博客也發表了《淺談boost.variant的幾種訪問方式》)。html
boost::variant<int, std::string> v; v = "Hello world"; std::cout << boost::get<std::string>(v) << std::endl;
使用boost::get來訪問,須要給出原始類型,而且這樣作不安全,若類型錯誤,程序將會拋出異常。安全
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官網網站