关于C++ variant 类型问题
2. _variant_t 这个在 comutil.h 文件内, 应该主要是windows 下的解决方案.。.
3.boost variant 和 boost any 麻烦的是需要引用boost库.
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 类型问题相关推荐
- Variant Analysis(变种分析)——使用已知漏洞发掘未知漏洞
文章目录 前言 1.variant Analysis (变种分析)是什么? 从哪里开始 2.常用技术 2.1 控制流分析(Control flow analysis (CFA)) 2.2 数据流分析 ...
- variant 字符串数组_VB数组部分核心知识总结
数组讲解 今天我们来学习有关数组的相关知识. 为了解决大批量的数据处理问题,VB中提供了数组(Array)变量.数组是一种重要的数据结构,在许多程序设计语言中,都要直接或间接用到数组这种数据结构. ...
- 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 ...
- 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 长读的 ...
- SAP Variant Conditions in Purchasing using reference characteristics【中英文双语版】
SAP Variant Conditions in Purchasing using reference characteristics SAP变式物料的采购如何玩转?看看这篇你就明白了! I ha ...
- SAP WM LRFMD中Variant参数的影响初探
SAP WM LRFMD中Variant参数的影响初探 目前的LRFMD设置: 仓库号360下账号dicksonjin的设置里,参数Variant为空. 为如下open TO做confirm, TO ...
- AJAX 传值数据类型问题
AJAX 传值数据类型问题 问题重现: 今天在用AJAX向后台传jobNo值的时候,发现无论怎样后端取到到的值都是null; 附图(前台AJAX,后台获值方法) 解决方法: Step1:一开始我以为是 ...
- C++ VARIANT 学习小记录
一:为什么会有这个? 目前,计算机语言有很多(大哥,为什么不能就那么一样呢?),如C++.Java,此外还有JavaScript.VBScript等脚本语言,它们自立门派,各自维护自己的数据类型. C ...
- 用variant的数据来推导基因表达 | Imputation of Expression Using PrediXcan
一个工具的逻辑得足够完善.意义足够重大,才有资格发在NG上. A gene-based association method for mapping traits using reference tr ...
最新文章
- 真厉害用python只要50行代码爬取黑丝美眉纯欲高清图
- ArrayList原理分析(重点在于扩容)
- java 通配符 日期_java – 使用带有通配符支持的SimpleDateFormat解析日期字符串(例如* yyyy * MM * dd * hh * mm * ss)...
- 如何分析案件的性质_律师如何综合分析一个案件
- 延时求和波束形成的MATLAB仿真
- 技术系列课|从NE264到NE265:视频编码技术缔造美好生活
- python如何用xpath爬取指定内容_Python利用Xpath选择器爬取京东网商品信息
- GitHub+Vue自动化构建部署
- C语言中的运算和运算符
- bzoj 2257[Jsoi2009]瓶子和燃料 数论/裴蜀定理
- 某超市销售数据的分析
- 现Revit BuiltInParameter.Model中枚举项,都可以用LabelUitls转成本地语言
- Java spring boot 开发中控Live10R指纹采集器linux(指纹登录系统)
- linux sticky,session_sticky命令
- 小程序推荐——那些好用实用的小程序(图片类、资讯类、工具类)
- 苹果公司CEO:混蛋乔布斯
- Redhat镜像-RHEL-官方镜像下载大全
- android系统文件误删,误删手机系统文件怎么恢复
- 计算机语言python-Python语言介绍
- 蓝桥杯 BASIC-21 基础练习 Sine之舞
热门文章
- 有一个一维数组,内放10个学生成绩,写一个函数当主函数调用此函数后嫩求出平均分、最高分和最低分
- html,bootstrap,js,jquery图片点击模态窗口放大图片,可以滚动常看长图
- 零经验产品经理,思维导图带你从入门到精通成为
- 解读ConnectBot-1 telnet、ssh常识
- ST MCSDK 初探
- 大话UWB技术之核心命脉:TDOA与TOF
- 七、Android定位与拨打电话、发送短信
- Vue最常见的面试题以及答案
- DELL 电脑 ubuntu20.04系统安装(最新最简版)
- java窗口上 显示学号和姓名_java编程 完成下图所示的图形用户界面设计,要求在界面中输入个人的班级、学号、姓名信息后,点击“...