Boost之Variant

来源:互联网 发布:土豆视频mac版下载 编辑:程序博客网 时间:2024/05/17 21:55

"The variant class template is a safe, generic, stack-based discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner. Whereas standard containers such as std::vector may be thought of as "multi-value, single type," variant is "multi-type, single value.

Problem

Many times, during the development of a C++ program, the programmer finds himself in need of manipulating several distinct types in a uniform manner. Indeed, C++ features direct language support for such types through its union keyword:

union { int i; double d; } u;

u.d = 3.14;

u.i = 3; // overwrites u.d (OK: u.d is a POD type)

C++'s union construct, however, is nearly useless in an object-oriented environment. The construct entered the language primarily as a means for preserving compatibility with C, which supports only POD (Plain Old Data) types, and so does not accept types exhibiting non-trivial construction or destruction:

union {

  int i;

  std::string s; // illegal: std::string is not a POD type!

} u;

union 的成员只能是POD类型。

//<boost程序完全开发指南>#include <boost/variant.hpp>#include <string>#include <iostream>using namespace boost;int main(){typedef variant<int, double, std::string> var_t;var_t v;assert(v.type() == typeid(int));assert(v.which() == 0);v = "variant demo";std::cout << *get<std::string>(&v) << std::endl; //使用get()函数取值try{std::cout << get<double>(v) << std::endl;}catch(bad_get &){std::cout << "bad_get" << std::endl;}std::cin.get();}

结果 

variant demo

bad_get


const std::type_info& type() const;

返回type_info对象,可判别variant当前的数据类型

“我们也可以使用自由函数get()来获取variant的值:

cout << get<string>(v)

“但get()函数通常不是最方便的访问方法,”它存在类型不安全的隐患,操作时必须查询variant当前值的类型。

改进版

//<me>#include <boost/variant.hpp>#include <string>#include <iostream>using namespace boost;typedef variant<int, double, std::string> var_t;void var_print(var_t & v){if(v.type() == typeid(int)){std::cout << get<int>(v) << std::endl;}else if(v.type() == typeid(double)){std::cout << get<double>(v) << std::endl;}else if(v.type() == typeid(std::string)){std::cout << get<std::string>(v) << std::endl;}else{std::cout << "error type" << std::endl;}}int main(){var_t v;v = "variant demo";var_print(v);v = 3.14;var_print(v);v = 909;var_print(v);std::cin.get();}


结果:

variant demo

3.14

909


函数var_print()将输入的variant对象输出,它使用了RTTI技术,效率低,并且一旦variant的模板参数发生变化,var_print()也必须改动,其if_else的处理结果也很不优雅。

Variant基于访问者模式提供了模板类static_visitor"

//<.修改代码>#include <boost/variant.hpp>#include <string>#include <iostream>using namespace boost;typedef variant<int, double, std::string> var_t;class print_visitor  :  public static_visitor<void> {public:void operator()(int i) const{std::cout << "It's an int: " << i << '\n';}void operator()(std::string s) const{std::cout << "It's a std::string: " << s << '\n';}void operator()(double d) const{std::cout << "It's a double: " << d << '\n';}};int main(){print_visitor v;var_t var;var = "variant demo";boost::apply_visitor(v, var);var = 3.14;boost::apply_visitor(v, var);var = 909;boost::apply_visitor(v, var);std::cin.get();}

结果:

It's a std::string: variant demo

It's a double: 3.14

It's an int: 909

二元访问器

“之前的访问器都只能操作一个variant对象,但操作两个variant对象的访问器也允许的,这在某些情况下是有用的,比如对两个variant进行比较。”

"注意,如果调用 get 失败(当 my_first_variant 所含值不是类型 int 时就会发生),会抛出一个类型为 boost::bad_get 的异常。"




原创粉丝点击