博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(原创)用c++11打造好用的any
阅读量:4353 次
发布时间:2019-06-07

本文共 2455 字,大约阅读时间需要 8 分钟。

  上一篇博文用c++11实现了variant,有童鞋说何不把any也实现一把,我正有此意,它的兄弟variant已经实现了,any也顺便打包实现了吧。其实boost.any已经挺好了,就是转换异常时,看不到详情,和boost.variant一样的问题。实现any比实现variant要简单,需要解决的关键技术是类型擦除,关于类型擦除我之前的博文有介绍,。

实现any的关键技术

  any能容纳所有类型的数据,因此当赋值给any时,需要将值的类型擦除才行,即以一种通用的方式保存所有类型的数据。这里可以通过继承去擦除类型,基类是不含模板参数的,派生类中才有模板参数,这个模板参数类型正是赋值的类型,在赋值时,将创建的派生类对象赋值给基类指针,基类的派生类中携带了数据类型,基类只是原始数据的一个占位符,通过多态,它擦除了原始数据类型,因此,任何数据类型都可以赋值给他,从而实现了能存放所有类型数据的目标。当取数据时需要向下转换成派生类型来获取原始数据,当转换失败时打印详情,并抛出异常。由于any赋值时需要创建一个派生类对象,所以还需要管理该对象的生命周期,这里用unique_ptr智能指针去管理对象的生命周期。

  下面来看看一个完整的any是如何实现的吧。

#include 
#include
#include
#include
struct Any{ Any(void) : m_tpIndex(std::type_index(typeid(void))){} Any(const Any& that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {} Any(Any && that) : m_ptr(std::move(that.m_ptr)), m_tpIndex(that.m_tpIndex) {} //创建智能指针时,对于一般的类型,通过std::decay来移除引用和cv符,从而获取原始类型 template
::type, Any>::value, U>::type> Any(U && value) : m_ptr(new Derived < typename std::decay
::type>(forward(value))), m_tpIndex(type_index(typeid(typename std::decay::type))){} bool IsNull() const { return !bool(m_ptr); } template
bool Is() const { return m_tpIndex == type_index(typeid(U)); } //将Any转换为实际的类型 template
U& AnyCast() { if (!Is
()) { cout << "can not cast " << typeid(U).name() << " to " << m_tpIndex.name() << endl; throw bad_cast(); } auto derived = dynamic_cast
*> (m_ptr.get()); return derived->m_value; } Any& operator=(const Any& a) { if (m_ptr == a.m_ptr) return *this; m_ptr = a.Clone(); m_tpIndex = a.m_tpIndex; return *this; }private: struct Base; typedef std::unique_ptr BasePtr; struct Base { virtual ~Base() {} virtual BasePtr Clone() const = 0; }; template
struct Derived : Base { template
Derived(U && value) : m_value(forward
(value)) { } BasePtr Clone() const { return BasePtr(new Derived
(m_value)); } T m_value; }; BasePtr Clone() const { if (m_ptr != nullptr) return m_ptr->Clone(); return nullptr; } BasePtr m_ptr; std::type_index m_tpIndex;};

 

测试代码:

void TestAny(){    Any n;        auto r = n.IsNull();//true    string s1 = "hello";    n = s1;    n = "world";    n.AnyCast
(); //can not cast int to string Any n1 = 1; n1.Is
(); //true}

再总结一下any的设计思路:Any内部维护了一个基类指针,通过基类指针擦除具体类型,any_cast时再通过向下转型获取实际数据。当转型失败时打印详情。

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

转载于:https://www.cnblogs.com/qicosmos/p/3420095.html

你可能感兴趣的文章
leecode第一百九十八题(打家劫舍)
查看>>
【BZOJ 1233】 [Usaco2009Open]干草堆tower (单调队列优化DP)
查看>>
07-3. 数素数 (20)
查看>>
写一个欢迎页node统计接口Py脚本(邮件,附件)-py
查看>>
计算两个日期之间的天数
查看>>
山东省第六届蓝桥杯 ///标题:三羊献瑞//c/c++组
查看>>
Unity火炬之光进度
查看>>
Android关于buildToolVersion与CompileSdkVersion的区别
查看>>
袋鼠云日志,日志分析没那么容易
查看>>
缓存穿透 缓存雪崩 缓存并发
查看>>
MySQL表的操作
查看>>
pt-table-checksum解读【转】
查看>>
matlab中类的定义和使用
查看>>
NIO(2):Channel
查看>>
Consistent Hashing算法
查看>>
C++基础--完善Socket C/S ,实现客户端,服务器端断开重连
查看>>
lvs,nginx反向代理,虚拟主机
查看>>
jquip,更简洁的代码
查看>>
【OJ】PAT-A解题报告
查看>>
文档语法
查看>>