一直想知道C++标准库有没有类似Qt下QVariant功能的类。整理了下网上关于这部分的说法:
1. std::variant 的实现是 C++17的, 使用需要考虑编译器的支持

2. _variant_t 这个在 comutil.h 文件内,  应该主要是windows 下的解决方案.。.

3.boost variant 和 boost any  麻烦的是需要引用boost库.

4. 在了就是自己编写,或者把boost等其他第三方库中关于这部分的分离出来单独使用
参考:http://bbs.csdn.net/topics/392042283
http://www.jb51.net/article/42985.htm       
以下为别人写的一个实现
variant类似于union,它能代表定义的多种类型,允许将不同类型的值赋给它。它的具体类型是在初始化赋值时确定

boost中的variant的基本用法:

复制代码代码如下:

typedef variant<int,char, double> vt;
vt v = 1;
v = '2';
v = 12.32;

  用variant一个好处是可以擦除类型,不同类型的值都统一成一个variant,虽然这个variant只能存放已定义的类型,但这在很多时候已经够用了。 取值的时候,通过get<T>(v)来获取真实值。然而,当T类型与v的类型不匹配时,会抛出一个bad_cast的异常来。boost的variant抛出的异常往往没有更多的信息,不知道到底是哪个类型转换失败,导致发生异常调试时很不方便。因此,就考虑用c++11去实现一个vairiant, 这个variant可以很容易知道取值时,是什么类型转换失败了。

打造variant需要解决的问题:
第一,要在内部定义一个char缓冲区。

  缓冲区用来存放variant的值,这个值是variant定义的多种类型中的某种类型的值,因此,这个缓冲区要足够大,能够存放类型最大(sizeof(Type))的值才可以,这个缓冲区的大小还必须在编译期计算出来。因此需要首先要解决的是variant值存放的缓冲区定义的问题。

第二,要解决赋值的问题。

  将值赋给vairiant时,需要将该值的类型ID记录下来,以便在后面根据类型取值。将值保存到内部缓冲区时,还需要用palcement new在缓冲区创建对象。另外,还要解决一个问题,就是赋值时需要检查variant中已定义的类型中是否含有该类型,如果没有则编译不通过,以保证赋值是合法的。

第三,要解决取值的问题。

  通过类型取值时,要判断类型是否匹配,如果不匹配,将详情打印出来,方便调试。

打造variant的关键技术:

1.找出最大的typesize
第一个问题中需要解决的问题是如何找出多种类型中,size最大的那个类型的size。看看如何从多种类型中找出最大类型的size。

复制代码代码如下:

template<typename T, typename... Args>
struct MaxType : std::integral_constant<int,
(sizeof(T)>MaxType<Args...>::value ? sizeof(T) : MaxType<Args...>::value) >

{};

template<typename T>
struct MaxType<T> : std::integral_constant<int, sizeof(T) >{};

通过这个MaxType就可以在编译期获取类型中最大的maxsize了:MaxType<Types...>::value。

2.类型检查和缓冲区中创建对象
第二个问题中需要解决两个问题,1.检查赋值的类型是否在已定义的类型中;2.在缓冲区中创建对象及析构;

先看看如何判断类型列表中是否含有某种类型:

复制代码代码如下:

template < typename T, typename... List >
struct Contains : std::true_type {};

template < typename T, typename Head, typename... Rest >
struct Contains<T, Head, Rest...>
    : std::conditional< std::is_same<T, Head>::value, std::true_type,

Contains<T, Rest...>>::type{};

template < typename T >
struct Contains<T> : std::false_type{};

通过bool值Contains<T, Types>::vaule就可以判断是否含有某种类型。

再看看如何在缓冲区中创建对象。

通过placement new在该缓冲区上创建对象,new(data) T(value);其中data表示一个char缓冲区,T表示某种类型。在缓冲区上创建的对象还必须通过~T去析构,因此还需要一个析构vairiant的帮助类:

复制代码代码如下:

template<typename... Args>
struct VariantHelper;

template<typename T, typename... Args>
struct VariantHelper<T, Args...> {
inline static void Destroy(type_index id, void * data)
{
if (id == type_index(typeid(T)))
((T*) (data))->~T();
else
VariantHelper<Args...>::Destroy(id, data);
}
};

template<> struct VariantHelper<>  {
inline static void Destroy(type_index id, void * data) { }
};

通过VariantHelper::Destroy函数就可以析构variant了。

3.取值问题
第三个问题中需要解决取值问题,如果发生异常,就打印出详细信息。这个就比较简单了,看后面的实现代码就行了。

c++11中完整的variant是如何实现的:

复制代码代码如下:

#include <typeindex>
#include <iostream>
#include <type_traits>
using namespace std;

template<typename T, typename... Args>
struct MaxType : std::integral_constant<int,
(sizeof(T)>MaxType<Args...>::value ? sizeof(T) : MaxType<Args...>::value) >

{};

template<typename T>
struct MaxType<T> : std::integral_constant<int, sizeof(T) >{};

template < typename T, typename... List >
struct Contains : std::true_type {};

template < typename T, typename Head, typename... Rest >
struct Contains<T, Head, Rest...>
: std::conditional< std::is_same<T, Head>::value, std::true_type, Contains<T,

Rest...>>::type{};

template < typename T >
struct Contains<T> : std::false_type{};

template<typename... Args>
struct VariantHelper;

template<typename T, typename... Args>
struct VariantHelper<T, Args...> {
inline static void Destroy(type_index id, void * data)
{
if (id == type_index(typeid(T)))
((T*) (data))->~T();
else
VariantHelper<Args...>::Destroy(id, data);
}
};

template<> struct VariantHelper<>  {
inline static void Destroy(type_index id, void * data) { }
};

template<typename... Types>
class Variant
{
typedef VariantHelper<Types...> Helper_t;
public:

Variant(void) :m_typeIndex(typeid(void))
{
}

~Variant()
{
Helper_t::Destroy(m_typeIndex, &m_data);
}

template<typename T>
bool Is()
{
return (m_typeIndex == type_index(typeid(T)));
}

template<typename T>
T& Get()
{
if (!Is<T>())
{
cout << typeid(T).name() << " is not defined. " << "current type is " <<

m_typeIndex.name() << endl;
throw std::bad_cast();
}

return *(T*) (&m_data);
}

template <class T, 
    class = typename std::enable_if<Contains<typename

std::remove_reference<T>::type, Types...>::value>::type>
    Variant(T&& value) : m_typeIndex(type_index(typeid(T)))
    {
        Helper_t::Destroy(m_typeIndex, &m_data);
        typedef typename std::remove_reference<T>::type U;
        new(m_data) U(std::forward<T>(value));
    }

private:
char m_data[MaxType<Types...>::value];
std::type_index m_typeIndex;
};

测试代码:

复制代码代码如下:

void TestVariant()
{
    typedef Variant<int, char, double> cv;
    int x = 10;

cv v =x;
    v = 1;
    v = 1.123;
    v = "";//compile error
    v.Get<int>(); //1
    v.Get<double>(); //1.23
    v.Get<short>(); //exception: short is not defined. current type is

int.
    v.Is<int>();//true
}

总结:c++11实现的variant在用法上和boost.variant保持一致,但实现更简洁,50行代码搞定。而且还能在抛出异常时提示详细信息,方便调试。

c++11 boost技术交流群:296561497,欢迎大家来交流技术。

关于C++ variant 类型问题相关推荐

  1. Variant Analysis(变种分析)——使用已知漏洞发掘未知漏洞

    文章目录 前言 1.variant Analysis (变种分析)是什么? 从哪里开始 2.常用技术 2.1 控制流分析(Control flow analysis (CFA)) 2.2 数据流分析 ...

  2. variant 字符串数组_VB数组部分核心知识总结

    ‍数组讲解 今天我们来学习有关数组的相关知识. 为了解决大批量的数据处理问题,VB中提供了数组(Array)变量.数组是一种重要的数据结构,在许多程序设计语言中,都要直接或间接用到数组这种数据结构. ...

  3. Accurate circular consensus long-read sequencing improves variant detection and assembly of a human

    Accurate circular consensus long-read sequencing improves variant detection and assembly of a human ...

  4. Ratatosk - Hybrid error correction of long reads enables accurate variant calling and assembly

    Ratatosk - Hybrid error correction of long reads enables accurate variant calling and assembly   长读的 ...

  5. SAP Variant Conditions in Purchasing using reference characteristics【中英文双语版】

    SAP Variant Conditions in Purchasing using reference characteristics  SAP变式物料的采购如何玩转?看看这篇你就明白了! I ha ...

  6. SAP WM LRFMD中Variant参数的影响初探

    SAP WM LRFMD中Variant参数的影响初探 目前的LRFMD设置: 仓库号360下账号dicksonjin的设置里,参数Variant为空. 为如下open TO做confirm, TO ...

  7. AJAX 传值数据类型问题

    AJAX 传值数据类型问题 问题重现: 今天在用AJAX向后台传jobNo值的时候,发现无论怎样后端取到到的值都是null; 附图(前台AJAX,后台获值方法) 解决方法: Step1:一开始我以为是 ...

  8. C++ VARIANT 学习小记录

    一:为什么会有这个? 目前,计算机语言有很多(大哥,为什么不能就那么一样呢?),如C++.Java,此外还有JavaScript.VBScript等脚本语言,它们自立门派,各自维护自己的数据类型. C ...

  9. 用variant的数据来推导基因表达 | Imputation of Expression Using PrediXcan

    一个工具的逻辑得足够完善.意义足够重大,才有资格发在NG上. A gene-based association method for mapping traits using reference tr ...

最新文章

  1. 真厉害用python只要50行代码爬取黑丝美眉纯欲高清图
  2. ArrayList原理分析(重点在于扩容)
  3. java 通配符 日期_java – 使用带有通配符支持的SimpleDateFormat解析日期字符串(例如* yyyy * MM * dd * hh * mm * ss)...
  4. 如何分析案件的性质_律师如何综合分析一个案件
  5. 延时求和波束形成的MATLAB仿真
  6. 技术系列课|从NE264到NE265:视频编码技术缔造美好生活
  7. python如何用xpath爬取指定内容_Python利用Xpath选择器爬取京东网商品信息
  8. GitHub+Vue自动化构建部署
  9. C语言中的运算和运算符
  10. bzoj 2257[Jsoi2009]瓶子和燃料 数论/裴蜀定理
  11. 某超市销售数据的分析
  12. 现Revit BuiltInParameter.Model中枚举项,都可以用LabelUitls转成本地语言
  13. Java spring boot 开发中控Live10R指纹采集器linux(指纹登录系统)
  14. linux sticky,session_sticky命令
  15. 小程序推荐——那些好用实用的小程序(图片类、资讯类、工具类)
  16. 苹果公司CEO:混蛋乔布斯
  17. Redhat镜像-RHEL-官方镜像下载大全
  18. android系统文件误删,误删手机系统文件怎么恢复
  19. 计算机语言python-Python语言介绍
  20. 蓝桥杯 BASIC-21 基础练习 Sine之舞

热门文章

  1. 有一个一维数组,内放10个学生成绩,写一个函数当主函数调用此函数后嫩求出平均分、最高分和最低分
  2. html,bootstrap,js,jquery图片点击模态窗口放大图片,可以滚动常看长图
  3. 零经验产品经理,思维导图带你从入门到精通成为
  4. 解读ConnectBot-1 telnet、ssh常识
  5. ST MCSDK 初探
  6. 大话UWB技术之核心命脉:TDOA与TOF
  7. 七、Android定位与拨打电话、发送短信
  8. Vue最常见的面试题以及答案
  9. DELL 电脑 ubuntu20.04系统安装(最新最简版)
  10. java窗口上 显示学号和姓名_java编程 完成下图所示的图形用户界面设计,要求在界面中输入个人的班级、学号、姓名信息后,点击“...