浅析C++中boost.variant的几种访问方法

Boost.Variant

Variant库包含一个不同于union的泛型类,用于在存储和操作来自于不同类型的对象。这个库的一个特点是支持类型安全的访问,减少了不同数据类型的类型转换代码的共同问题。

Variant 库如何改进你的程序?

•对用户指定的多种类型的进行类型安全的存储和取回

•在标准库容器中存储不同类型的方法

•变量访问的编译期检查

•高效的、基于栈的变量存储

Variant 库关注的是对一组限定类型的类型安全存储及取回,即非无类的联合。Boost.Variant 库与 Boost.Any 有许多共同之外,但在功能上也有不同的考虑。在每天的编程中通常都会需要用到非无类的联合(不同的类型)。保持类型安全的一个典型方法是使用抽象基类,但这不总是可以做到的;即使可以做得,堆分配和虚拟函数的代价也可能太高。你也可以尝试用不安全的无类类型,如 void* (它会导致不幸),或者是类型安全得无限制的可变类型,如 Boost.Any. 这里我们将看到 Boost.Variant,它支持限定的可变类型,即元素来自于一组支持的类型。

下面将浅谈variant的几种访问方法,一起来学习学习吧。

使用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 << get<int>(v) << std::endl;
  }
  else if (v.type() == typeid(std::string))
  {
    std::cout << 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会对程序性能有一定影响。

使用访问者模式

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支持多少类型。

总结

以上就是这篇文章的全部内容,希望本文的内容对大家学习或者使用C++能有所帮助,如果有疑问大家可以留言交流。谢谢大家对我们的支持。

(0)

相关推荐

  • C++之Boost::array用法简介

    本文实例讲述了c++里支持静态数组的容器:boost.array.分享给大家供大家参考.具体分析如下: 很多C++程序员都认为boost.array很有可能出现在下一代标准库里.对于boost.array的用法有一个基本的了解是很有必要的. 1. 为什么我们需要固定大小的数组的容器 首先,固定大小的数组还是很常见的,虽然stl提供了vector,但是vector作为动态可增长的数组,比静态数组多了一点开销,这在一些人看来是无法忍受的.c++里也需要提供固定大小容量的数组容器,当然,性能可以和普通

  • C++中的friend友元函数详细解析

    友元函数是可以直接访问类的私有成员的非成员函数.它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend. 我们已知道类具有封装和信息隐藏的特性.只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的.非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性.另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运

  • 使用设计模式中的单例模式来实现C++的boost库

    线程安全的单例模式 一.懒汉模式:即第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例. 需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety. 使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈. 1.静态成员实例的懒汉模式: class Singleton { private: static Singleton* m_instance; Sing

  • C++中Boost库裁剪与其应用详解

    前言 Boost 库涵盖的范围极广,有字符串和文本处理相关子库比如 format 库和 regexp 库,有容器相关子库比如 variant 库(和 Qt 的 QVariant 有得一拼),有迭代器子库比如 tokenizer 库(可以把字符进行 tokenize),还有算法.函数对象和高阶编程相关子库如functional 库.lambda 库和 signal 库,还有泛型编程.模板编程子库如 call traits.mpl,还有并发编程相关的 thread 库,等等等等. Boost 是如此

  • C++之boost::array的用法

    本文实例讲述了C++之boost::array的用法,分享给大家供大家参考.具体如下: 复制代码 代码如下: #include <string>  #include <iostream>  #include <boost/array.hpp>  #include <algorithm>  using namespace std;  int main()  {      boost::array<int, 5> array_temp = {{12,

  • C++中的哈希容器unordered_map使用示例

    随着C++0x标准的确立,C++的标准库中也终于有了hash table这个东西. 很久以来,STL中都只提供<map>作为存放对应关系的容器,内部通常用红黑树实现,据说原因是二叉平衡树(如红黑树)的各种操作,插入.删除.查找等,都是稳定的时间复杂度,即O(log n):但是对于hash表来说,由于无法避免re-hash所带来的性能问题,即使大多数情况下hash表的性能非常好,但是re-hash所带来的不稳定性在当时是不能容忍的. 不过由于hash表的性能优势,它的使用面还是很广的,于是第三方

  • C++运算符重载的方法详细解析

    运算符重载实质上是函数的重载 重载运算符的函数一般格式如下: 函数类型    operator  运算符名称    (形参表列) {对运算符的重载处理} 例如,想将"+"用于Complex(复数)的加法运算,函数的原型可以是这样的: 复制代码 代码如下: Complex operator + (Complex & c1,Complex &c2); 其中,operator是关键字,时候专门用于定义重载运算符的函数的,运算符名称就是C++提供给用户的预定运算符. 注意:函数

  • 基于C++全局变量的声明与定义的详解

    (1)编译单元(模块)在VC或VS上编写完代码,点击编译按钮准备生成exe文件时,编译器做了两步工作:第一步,将每个.cpp(.c)和相应的.h文件编译成obj文件:第二步,将工程中所有的obj文件进行LINK,生成最终.exe文件.那么,错误可能在两个地方产生:一个,编译时的错误,这个主要是语法错误:一个,链接时的错误,主要是重复定义变量等.编译单元指在编译阶段生成的每个obj文件.一个obj文件就是一个编译单元.一个.cpp(.c)和它相应的.h文件共同组成了一个编译单元.一个工程由很多编译

  • c++ vector(向量)使用方法详解(顺序访问vector的多种方式)

    vector 是向量类型,它可以容纳许多类型的数据,如若干个整数,所以称其为容器.vector 是C++ STL的一个重要成员,使用它时需要包含头文件: 复制代码 代码如下: #include<vector>; 一.vector 的初始化:可以有五种方式,举例说明如下: (1) vector<int> a(10); //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的.(2)vector<int> a(10,

  • C++ boost 时间与日期处理详细介绍

    boost 时间与日期处理 导视: 类 特点 缺点 说明 timer 计时基类 不适合大跨度时间 适用大部分的普通计时 progress_timer 继承自timer 可以自动写入流中 只精确到0.01s 如果需要更精确,可派生个类,调用stream的precision设置 progress_display 图形化显示进度 只能输出到cout 如果还有其他输出则会干扰进度显示. 折中的办法是重新显示 pd.restart(size); pd+= pNum; date 日期结构,时间点 -- da

  • c++中new的三种用法详细解析

    一. 简介new有三种使用方式:plain new,nothrow new和placement new. (1)plain new顾名思义就是普通的new,就是我们惯常使用的new.在C++中是这样定义的:    void* operator new(std::size_t) throw(std::bad_alloc);    void operator delete(void *) throw(); 提示:plain new在分配失败的情况下,抛出异常std::bad_alloc而不是返回NU

  • C++之BOOST字符串查找示例

    本文实例讲述了C++中BOOST字符串查找的方法,分享给大家供大家参考.具体方法如下: BOOST  字符串查找示例 复制代码 代码如下: #include <string>  #include <iostream>  #include <algorithm>  #include <functional>  #include <boost/algorithm/string/case_conv.hpp>  #include <boost/al

随机推荐